SERIAL und letzte ID via PDO

Hi,
möchte DBs von MySQL auf PG migrieren, dabei sind mir nach einigen Tests zwei grundlegende Dinge aufgefallen, für welche ich derzeit unter PHP keine richtige Lösung finde ohne nur die SQL-Abfragen anpassen zu müssen.
Ich möchte eigentlich nicht das DB-Modell ändern.

  • Die in MySQL enthaltene ID ist als Autowert deklariert in der PG als SERIAL über ein Zugriff soll die letzte eingefügte ID der Verbindung über PDO LastInsertID(…) ermittelt werden, leider immer ‚false’. Wichtig ist mir ein Zugriff über PDO!

  • Beim Einfügen von mehreren Datensätzen in einer for-Schleife entstehen Lücken für die ID in der PG-Datenbank und zwar immer beim Einfügen des ersten Datensatzes vor dem Block in der for-Schleife (nicht sehr schön!).

Beides sind zwar keine schlimmen Probleme, behindern aber empfindlich einen schmerzlosen Übergang zu PostgreSQL.
Hat jemand gegebenenfalls dazu Lösungen?

Behandeln wir das zweite Problem zuerst: wie sieht dein Code aus, der die Daten innerhalb der Schleife einfügt?

Ach so: SERIALs dürfen per Definition Lücken aufweisen, wenn du lückenlose IDs benötigst, lies jeweils die letzte ID in der Tabelle aus und addiere eins drauf.

Noch ein grundsätzlicher Hinweis: die (unsere) Erfahrung lehrt, dass man bei einem Umstieg von Mysql trotzdem das Datenmodell wenigstens kritisch prüfen sollte. Das ist der richtige Zeitpunkt dafür und ich habe noch kein einziges Projekt gesehen, das Tabellen und Struktur einfach 1:1 übernommen und später keine Probleme gehabt hat.

Du wirst currval() nutzen wollen, geht ganz sicher auch mit PDO.
PostgreSQL: Documentation: Manuals: PostgreSQL 8.3: Sequence Manipulation Functions

  • Beim Einfügen von mehreren Datensätzen in einer for-Schleife entstehen Lücken für die ID in der PG-Datenbank und zwar immer beim Einfügen des ersten Datensatzes vor dem Block in der for-Schleife (nicht sehr schön!).

Sequenzen können Löcher haben, ja. Das ist normal. Sie entstehen, wenn z.B. ein INSERT nicht geklappt hat. Du solltest also erstens) Dich damit abfinden und zweitens) schauen, ob wirklich alles gespeichert wurde.



Andreas

Pfffft. Wenn dann, dann muß man natürlich aufpassen, daß nicht 2 oder mehr Prozesse das tun. Hint: Sperren setzen. SERIAL ist extra dafür da, exakt das zu verhindern, mit der Konsequenz, daß auch mal Lücken drin sein können.


Andreas

Danke,

currval() für PostgeSQL ist offensichtlich der einzig richtige Weg um gleiches wie unter MySQL mit PDO und lastInsertID() zu erreichen.

Die Syntax ist ein wenig grausam.
Vielleicht hilft’s einem anderen, ich tat mich jedenfalls schwer.

Beispiel:
Statt Feld “ID” in der Tabelle ‘Test’ muss diese Feldbezeichnung ‘“Test_ID_seq”’ gewählt werden, zwingend mit einfachen und den doppelten Anführungszeichen!

für PHP so notiert:
$db->query(‘SELECT currval(’."’".’“Test_ID_seq”’."’".’) AS “TTT”’)

Huch, was läuft hier schief?:

test=# create table foobar (id serial);
NOTICE:  CREATE TABLE will create implicit sequence "foobar_id_seq" for serial column "foobar.id"
CREATE TABLE
Zeit: 89,208 ms
test=*# insert into foobar values (default);
INSERT 0 1
Zeit: 0,325 ms
test=*# select currval('foobar_id_seq');
 currval
---------
       1
(1 Zeile)

Andreas

Abgesehen davon gibt es Funktionen, denen man Tabellenname und Spaltenname sagt und die suchen sich selbstständig den Sequencenamen heraus. Damit muss man sich überhaupt nicht herumschlagen.

Näheres steht in der Dokumentation zu den SERIAL Datentypen.

also einfach eine INSERT - Anweisung dem PDO wie eine SELECT anweisung behandeln lassen …

INSERT into myTable (id, bla blub, …) VALUES (DEFAULT, …) RETURNING id

dann solltest du ein Resultset erhalten, welches dir die ID im Feld id liefert …

Ach ja … Lücken sollten bei einem EIN-Prozess Zugriff auf die DB nicht auftreten - wenn keine INSERT-Fehler (Constraint-Verletzungen) auftraten… auch wenn das lt. Definition fuer Serials zulässig ist - Und schon garnicht in einer neuen leeren DB … Ich wuerde mal den Code prüfen

Gruß