Discussion:
Primärschlüssel einer Access-Tabelle ermitteln
(zu alt für eine Antwort)
Frank Rothweiler
2011-04-16 14:11:26 UTC
Permalink
Für eine automatisierte Datenbank-Konvertierung (Access –> Firebird)
benötige ich das Feld jeder Tabelle, das einen Primärschlüssel
darstellt. Ich greife über die dbGO-Komponenten (ADO) auf eine
Access-Datenbank zu.

Über Feldeigenschaften ist die Information darüber, ob ein Feld ein
AutoInc-Feld ist, abrufbar:

FOR i := 0 TO ADOdataset.FieldDefs.Count -1 DO
IF ADOdataset.FieldDefs[i].DataType = ftAutoInc THEN IndexFeld := i;

in einer Schleife über alle Felder (Spaltennamen) hinweg funktioniert.

Nun gibt es aber Tabellen, die zwar einen Primärschlüssel besitzen, aber
kein AutoInc-Feld. So z.B. wenn der Primärschlüssel zu einem Feld mit
Artikelnummern gehört. Wie finde ich in diesem Fall heraus, welche
Spalte einer Tabelle den Primärschlüssel darstellt?

Mittels der Attribute der Felddefinitionen ...

faHiddenCol, faReadonly, faRequired, faLink, faUnNamed, faFixed

... ist es nicht möglich, einen Primärschlüssel zu ermitteln.

Ich habe sogar bereits mit den Units ADODB_TLB und ADOX_TLB
herumexperimentiert (generiert aus Microsoft ADO Data Conrol 6.0 bzw.
Microsoft ADO Ext. 2.8 for DLL and Security), scheitere aber an den
Attributen:

FUNCTION TDatMod.TabelleAnlegen(Sender: TObject; TabName : WideString;
VAR Ergebnis : STRING) : BOOLEAN;

VAR
Table : _Table;
Column : _Column;
Catalog : _Catalog;
i,
PrimaryFeld : INTEGER;
PrimaryFeldName : WideString;

BEGIN
Result := FALSE;
...

Catalog := CoCatalog.Create;
Catalog.Set_ActiveConnection(ADOConMain.ConnectionObject);
Table := Catalog.Tables[TabName];

FOR i := 0 TO Table.Columns.Count -1 DO
IF Column.Attributes = adKeyPrimary
THEN
BEGIN
PrimaryFeld := i;
PrimaryFeldName := Table.Columns[i].Name;
END;

...
END;

In ADOX_TLB ist definiert:

const
adKeyPrimary = $00000001;
adKeyForeign = $00000002;
adKeyUnique = $00000003;

Zur Laufzeit hat Column.Attributes den Wert 2, wenn das Feld[i] einen
Primärschlüssel hat und gleichzeitig ein AutoInc-Feld ist. In der
anderen Tabelle, die lediglich eine Artikelnummer (LongInteger,
Primärschlüssel) und eine Warenbezeichnung (Text (200)) enthält, hat die
Artikelnummer-Spalte den Attributwert 3 und die Warentext-Spalte den
Wert 2. Ich blicke da ehrlich gesagt nicht so recht durch ...
Peter
2011-04-17 09:34:01 UTC
Permalink
Post by Frank Rothweiler
Für eine automatisierte Datenbank-Konvertierung (Access –> Firebird)
benötige ich das Feld jeder Tabelle, das einen Primärschlüssel
darstellt. Ich greife über die dbGO-Komponenten (ADO) auf eine
Access-Datenbank zu.
Über Feldeigenschaften ist die Information darüber, ob ein Feld ein
Da scheint es ein Mißverständnis deinerseits darüber zu geben, was ein
Primärschlüssel eigentlich ist. Du gehst davon aus, daß das irgendwie
ein Attribut einer Spalte ist. Das ist falsch. Ein Primärschlüssel ist
ein Constraint (keine Ahnung, was das gängige deutsche Äquivalent dafür
ist). Schließlich kann ein Primärschlüssel aus mehreren Spalten
zusammengesetzt werden, er kann also kein Attribute einer Spalte sein.
Ein Constraint ist ein Attribute einer Tabelle.

Das ADO Table-Objekt hat eine Collection mit Namen Keys. Die dort zu
findenden Key-Objekte beschreiben die primary und foreign (und unique)
Keys der Tabelle. Eine Eigenschaft von Key ist Type (_Type in Delphi),
und das ist die Eigenschaft, die Du auf adKeyPrimary testen mußt. Key
hat auch eine Collection namens Columns, und da findest Du die Spalten,
aus denen der Key zusammengesetzt ist.

http://msdn.microsoft.com/en-us/library/ms676123%28v=vs.85%29.aspx
--
Peter Below
Frank Rothweiler
2011-04-17 13:42:15 UTC
Permalink
Post by Peter
Da scheint es ein Mißverständnis deinerseits darüber zu geben, was ein
Primärschlüssel eigentlich ist. Du gehst davon aus, daß das irgendwie
ein Attribut einer Spalte ist. Das ist falsch. Ein Primärschlüssel ist
ein Constraint (keine Ahnung, was das gängige deutsche Äquivalent dafür
ist). Schließlich kann ein Primärschlüssel aus mehreren Spalten
zusammengesetzt werden, er kann also kein Attribute einer Spalte sein.
Ein Constraint ist ein Attribute einer Tabelle.
Das war schonmal sehr erhellend ;-)
Post by Peter
Das ADO Table-Objekt hat eine Collection mit Namen Keys. Die dort zu
findenden Key-Objekte beschreiben die primary und foreign (und unique)
Keys der Tabelle. Eine Eigenschaft von Key ist Type (_Type in Delphi),
und das ist die Eigenschaft, die Du auf adKeyPrimary testen mußt. Key
hat auch eine Collection namens Columns, und da findest Du die Spalten,
aus denen der Key zusammengesetzt ist.
Diese Lösung hat (fast) auf Anhieb funktioniert:

VAR
...
IdxList : TStringList;
iz : INTEGER;
...

BEGIN
...

IdxList := TStringList.Create;
Catalog := CoCatalog.Create;

Catalog.Set_ActiveConnection(ADOConMain.ConnectionObject);
Table := Catalog.Tables[TabName];

iz := Table.Keys.Count;
IF iz > -1 THEN
FOR i := 0 TO iz-1 DO
BEGIN
TabKey := Table.Keys.Item[i];
IF TabKey.type_ = adKeyPrimary THEN
FOR m := 0 TO TabKey.Columns.Count -1 DO
IdxList.Append(TabKey.Columns[m].Name);
END;

IdxList.SaveToFile(Pfad + 'IndexListe' + TabName + '.txt');

...
END;

Und nun steht in meiner Datei IndexListeTabname.txt deutlich lesbar der
Spaltenname, der den Primärschlüssel enthält – in diesem Fall nur einer.
Wunderbar :-))) hatte ich mich doch zuvor Nächte mit diesem Problem
herumgeschlagen ... Dafür gebührt dir mein ausdrücklicher Dank!
Post by Peter
http://msdn.microsoft.com/en-us/library/ms676123%28v=vs.85%29.aspx
Tja, dort hätte ich eigentlich als erstes nachschlagen sollen ... ist
nun für alle Zeiten in meine Bookmarksammlung einsortiert.

Loading...