[Delphi] Kolom toev. aan bestaande tabel

Pagina: 1
Acties:

  • marenk_vos
  • Registratie: Augustus 2001
  • Laatst online: 23-07 13:21
Ik heb een serie tabellen die allemaal apart worden opgeslagen per aangemaakte calculatie in een bestaande applicatie. Nu zit er een verschil tussen calculaties/tabellen die 1 jaar geleden gemaakt zijn en die kort geleden gemaakt zijn. De nieuwe tabellen hebben een aantal kolommen extra.

Nu wil ik bij het openen van een oude calculatie/tabel checken of de extra kolommen aanwezig zijn, als dit niet zo is moeten deze aangemaakt worden. 1 Tabel kan maar door 1 persoon tegelijk geopend worden (geen multiuser probleem dus)

Mijn vraag is nu dus hoe doe ik dat. Het gaat om dbase tabellen, het liefst gebruik ik het TTable component van Delphi, echter kan ik daar geen restructure oid vinden. Wel een create maar dan maakt hij een geheel nieuwe tabel en overschrijft hij de oude (inclusief inhoud).

Dell XPS 17 Intel i7 2630 Nvidia GT555 3Gb Hd1: OCZ Vertex 2 SSD 60 GB Hd2: 500Gb


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:04
Je zult een alter-table statement moeten uitvoeren.

Eigenlijk getuigt dit niet van een goed databank-ontwerp als je uw tabellen zoveel moet gaan aanpassen. Als ik het goed begrijp, maak je ook ieder jaar ofzo een nieuwe tabel aan? Ik zie daar het nut niet van in hoor... Sterker nog, als je dat zo doet, heb je eigenlijk geen goed datamodel.

https://fgheysels.github.io/


  • Sjnirk
  • Registratie: Maart 2001
  • Laatst online: 27-03-2025

Sjnirk

Hie vrieve

Kun je misschien es hier je schrijven wat je precies wilt, misschien is er wel een veel beter dbase-design voor, of niet :)

Bikkelen gebeurt pas na 2:00


  • tfk__66
  • Registratie: September 2002
  • Laatst online: 29-10-2025

tfk__66

OS1: Fedora Linux, OS2: W10

Whoami heeft daar inderdaad gelijk in. Met een goed datamodel wordt alleen de data toegevoegd/gewijzigd, niet de tabellen. Maarja, je hebt de situatie nu, dus laten we die het hoofd bieden.

Misschien is het een idee om het met een tquery te doen.

var
aQuery: TQuery;

...

aQuery := TQuery.Create(nil);
try
aQuery.sql := 'select kolomnamendienieuwzijn from detabel';
aQuery.open;
if aQuery.eof then
{hee geen data dus geen kolommen}
else
{ wel data dus kolommen }
end;
finally
aQuery.Free;
end;

Foutjes voorbehouden.

GA-Z170XP-SLI - i7 6700K 4.0GHz - 16GB DDR3 - Corsair 300R Wnd - Corsair CX750M - AMD 7950 3GB


  • Delphi32
  • Registratie: Juli 2001
  • Laatst online: 31-08 21:58

Delphi32

Heading for the gates of Eden

flappie__66 schreef op 11 september 2002 @ 16:06:
Misschien is het een idee om het met een tquery te doen.

var
aQuery: TQuery;

...

aQuery := TQuery.Create(nil);
try
aQuery.sql := 'select kolomnamendienieuwzijn from detabel';
aQuery.open;
if aQuery.eof then
{hee geen data dus geen kolommen}
else
{ wel data dus kolommen }
end;
finally
aQuery.Free;
end;

Foutjes voorbehouden.
Dat gaat niet werken. Als in detabel de kolomnamendienieuwzijn niet bestaan, krijg je een Exception om je oren :)
Je moet vanaf aQuery.Open vervangen door
code:
1
2
3
4
5
6
try
  aQuery.Open;
  result := TRUE; //yes, de kolommen zijn er
except
  result := FALSE; //Nope, geen nieuwe kolommen aanwezig
end;

  • marenk_vos
  • Registratie: Augustus 2001
  • Laatst online: 23-07 13:21
Jullie hebben helemaal gelijk er is inderdaad geen goed data-ontwerp geweest. Er zijn nog wel meer problemen. Het is nu eenmaal zo.

Het gaat dus om verschillende kleinere tabellen. Deze tabellen staan in de zogenaamde projectmappen. In 1 projectmap zit per calculatie 1 tabel. Een calculatie bestaat uit 3 zogenaamde FORMULA ONE spreadsheet bladen waarvan 1 blad de layout is van een hele serie artikelen. De artikelen op dit blad loopt synchroon in 1 dbase tabel. Per calculatie dus 1 tabel. Het gevold hiervan is dat duizend calculaties bestaan uit 3000 spreadsheet bladen en 1000 kleine dbase tabellen.

Ik zou dit kunnen veranderen, de verschillende spreadsheets blijven zowiezo wel, het gaat om meer gegevens dan alleen artikelen.

Ik zou 1 grote centrale tabel kunnen maken maar in de huidige vorm lijkt me dit niet verstandig ik denk dat die ene tabel dan te groot zal worden. En over een aantal maanden gaan we toch overstappen op mysql of zo. Tot die tijd wil ik extra kolommen aamaken als tussen oplossing gaan gebruiken

Dell XPS 17 Intel i7 2630 Nvidia GT555 3Gb Hd1: OCZ Vertex 2 SSD 60 GB Hd2: 500Gb


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:12

Creepy

Tactical Espionage Splatterer

Hmm... wat is te groot?? DBase tabellen gaan makkelijk over de 60-70.000 heen, met een fatsoenlijke performance (mits je db ontwerp goed is ;) )

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • marenk_vos
  • Registratie: Augustus 2001
  • Laatst online: 23-07 13:21
Hebben we het wel over hetzelfde dbase? Het dbase dat 1 tabel per .dbf bestand is. Wat is nu het nieuwste dbase?

Dell XPS 17 Intel i7 2630 Nvidia GT555 3Gb Hd1: OCZ Vertex 2 SSD 60 GB Hd2: 500Gb


  • marenk_vos
  • Registratie: Augustus 2001
  • Laatst online: 23-07 13:21
De volgende code geeft deze foutmelding: Error no resultset, unable to place cursor handle

de extra kolom is wel toegevoegd:

aQuery := TQuery.Create(nil);
try
aQuery.DatabaseName:=path;
aQuery.SQL.Clear;
aQuery.SQL.Add('select art_naam from '''+tabelnaam+'''');
aQuery.open;
aQuery.Free;
except
try
aQuery := TQuery.Create(nil);
aQuery.DatabaseName:=path;
aQuery.SQL.Clear;
aQuery.SQL.Add('alter table '''+tabelnaam+''' add art_naam char(30)');
aQuery.open;
except
result:=false;
end;

end;

Dell XPS 17 Intel i7 2630 Nvidia GT555 3Gb Hd1: OCZ Vertex 2 SSD 60 GB Hd2: 500Gb


  • tfk__66
  • Registratie: September 2002
  • Laatst online: 29-10-2025

tfk__66

OS1: Fedora Linux, OS2: W10

Bij het altertable statement i.p.v aQuery.Open aQuery.Execute (met select statements altijd Open en bij statements waarmee je data veranderd of toevoegd Open - Execute natuurlijk, wat een }:O ben ik ook :) ).

Dat nog ff dit:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
aQuery := TQuery.Create(nil);
try  //hee, deze is nieuw...

try
  aQuery.DatabaseName:=path;
  aQuery.SQL.Clear;
  aQuery.SQL.Add('select art_naam from '''+tabelnaam+'''');
  aQuery.open;
except
  try
    aQuery.DatabaseName:=path;
    aQuery.SQL.Clear;
    aQuery.SQL.Add('alter table '''+tabelnaam+''' add art_naam char(30)');
    aQuery.Execute;
  except
    result:=false;
  end;
end;

finally //en dit stukkie ook...
  aQuery.Free;
end;


op deze manier geef je aQuery altijd vrij. Wat er ook fout mocht gaan.

[ Voor 0% gewijzigd door tfk__66 op 12-09-2002 16:43 . Reden: fuotje :) ]

GA-Z170XP-SLI - i7 6700K 4.0GHz - 16GB DDR3 - Corsair 300R Wnd - Corsair CX750M - AMD 7950 3GB


  • Paul
  • Registratie: September 2000
  • Laatst online: 17:21
Zoiets hadden wij ook.

En slecht datamodel, ach, als er na 3 jaar weer eens functionaliteit wordt toegevoegd (zoals een tijd terug, emailadres toevoegen bij een relatiebestand), dan vind ik dat wel meevallen. In ons geval was het iig geen onderdeel van de originele applicatie.

Hoe dan ook.
Wij maken al onze tabellen met een unit die we TableManager hebben genoemd.
Op het moment dat je die aanmaakt, controleerd die allemaal zaken, en op het moment dat je een tabel opent, kijkt hij of deze al bestaat. Zo niet, simpel, aanmaken.

Daaruit volgt dat in die Tablemanager alle tabeldefinities staan. Hier kun je dus een tellertje bijzetten hoeveel kolommen er zijn.
Uit TTable.FieldDefs kun je het aantal velden halen, verschilt dat met het tellertje dat je hebt, dan heb je dus te maken met een oude tabel.

Oplossing:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
CopyFile(huidigeMap + bestandsNaam, backupMap + bestandsNaam);
OudTable := TTable.Create(nil);
OudTable.DatabaseName := backupMap;
OudTable.TableName := bestandsNaam;
OudTable.TableType := ttDbase;

OudTable.Active := true;
OudTable.First;

// Ik weet niet hoe het daar gaat, maar bij ons is dit de normale manier van
// het aanmaken van een tabel:
NieuwTable := TableManager.GiveTable(welke_wil_je_hebben); 
NieuwTable.Active := true;

while not OudTable.Eof do
  begin
    NieuwTable.Append;
    voor i = 0 tot aan totaal aantal velden in NieuwTable do
      begin
        try
          NieuwTable[NieuwTable.IndexDefs.NameOf(i)] := 
            OudTable[NieuwTable.IndexDefs.NameOf(i)]; // OID... Iig de naam opzoeken
        except
          // Exception komt voor bij nietbestaande velden in OudTable;
        end;
      end;
    NieuwTable.Post;
    OudTable.Next;
  end;


Eventueel nog wat checks als de nieuwe velden required zijn, maar (nu dus) leeg, dan kun je een default waarde invullen.
Is misschien een vrij ranzige methonde, je kunt de try..except eruitwerken door iedere keer te controleren in de IndexDefs of de veldnaam bestaat en zo, maar zo updaten ze bij ons dus iedere nieuwe versie die een klant krijgt (onderhoudscontract) alle ondertussen 130 tabellen. Wij doen het dus neit on the fly, maar in een apart programma, bij een nieuwe release.

Wat je eventueel nog kunt doen om vooral bij grote tabellen (en dat is al vanaf 3k records DUIDELIJK merkbaar als je redelijk wat indexen hebt) de snelheid omhoog te jagen, is bij het aanroepen / maken van de nieuwe tabellen de indexen nog niet toe te voegen, maar deze naderhand toe te voegen. Dat brengt wel een grotere overhead mee, want nu moet de update-procedure wel ALLE indexen van alle tabellen kennen, wat dan ook de reden is dat we dat bij ons niet doen.

Ik heb zo de code niet bij de hand (zit thuis atm) dus ik kan wat vergeten zijn / verkeerd hebben, maar zoals hierboven is wel het algemene idee :)


:o :o :o :o :o :o :o :o :o :o :o :o

Aan het alter table statment heeft nog nooit iemand hier (bij ons) gedacht... Komt omdat wij alles met TTable doen ipv met TQuery.

Hoe dan ook, zo kun je het beste uit 2 werelden combineren, want dan kun je met TTable.FieldDefs de veldnamen opzoeken, kijken welke je mist, en die dan met het SQL-statement toevoegen. Dan ben je ook van die try..except af, want eigenlijk is dit geen fout-afhandeling :P

"Your life is yours alone. Rise up and live it." - Richard Rahl
Rhàshan - Aditu Sunlock


  • marenk_vos
  • Registratie: Augustus 2001
  • Laatst online: 23-07 13:21
Ik denk dat ik nu wel genoeg informatie heb.... bedankt allemaal voor jullie moeite....

Dell XPS 17 Intel i7 2630 Nvidia GT555 3Gb Hd1: OCZ Vertex 2 SSD 60 GB Hd2: 500Gb

Pagina: 1