insert mit id(serial)

ich oute mich jetzt mal als mysql-umsteiger:

insert into table (id,word) values (0,'bla')

hat da prima funktionert, id wurde automatisch zu einer primär-id.

Mr. Postmaster schmeisst mir bei diesem Query nur einen Error. (ID ist als serial und primary definiert).

Ich hab das jetzt so gelöst:

insert into table (id,word) values((select max(id)+1 from table),'bla');

Kennt Postgresql für Primärschlüssel eine elegantere Lösung?

nextval(‘table_id_seq’) hab ich versucht - das liefert aber nur ein “duplicate key violates unique constraint “words_pkey”” zurück. Ich vermute mal, das kommt, weil in der id-reihe der tabelle einige “Löcher” sind.

Thomas

Hallo gnoerz,

hier sind alle willkommen. Ich habe auch schon mit MySQL gearbeitet.

In PostgeSQL wird keine Spalte automatisch zum Primary-Key. Das kann nur der Entwickler bestimmen.

Ist in einer Tabelle eine Spalte von Typ SERIAL, braucht Du Dich beim Einfügen eines neuen Datensatzes nicht um diese Spalte kümmern. Sie wird beim Einfügen eines neuen Datensatzes automatisch weiter gezählt.

Dann würde Dein Befehl wie folgt aussehen:

insert into table (word) values('bla');

Für weitere Hilfe sind genauere Angaben nötig!



mfg

fristo

hm - ich hab mit phppgadmin eine primary id-spalte als serial angelegt - daraus wird dann eine integer-spalte mit einem default von “nextval(’_id_seq’::regclass)”

ich hab nochmal rumprobiert und bin jetzt vollends verwirrt:
in einer tabelle funktioniert das INSERT ohne ID problemlos.

In einer anderen, identisch konfigurierten Tabelle funktioniert das nicht…
“duplicate key violates unique constraint “domainnames_pkey””

was in einer tabelle funktioniert, funktioniert in der anderen nicht, obwohl die identisch aussehen ?!?

ich fahr mal die clients runter und mach alle indizes neu…

das passiert mir manchmal wenn ich einen datensatz eingebe und die id quasi per hand mit eingebe so wie du am anfang. dabei wird die sequenz nicht mit hoch gezählt und wenn du dann versuchst die nächste id automatisch vergeben zu lassen versucht er einen bereits existierenden key einzufügen. war zumindest bei mir so…

Crypi

ich gehe grade den ganz bitteren weg:

  • neue tabelle erstellt
  • 8 millionen einträge der alten in die neue tabelle importieren (id.alt=oldid.neu)
  • 2x8 millionen id-referenzen in zwei weiteren tabellen von id.alt auf id.neu updaten

die insert-lösung mit subselect max(id)+1 hätte gut funktioniert, wenn nicht bis zu vierzig clients gleichzeitig inserts in der tabelle durchführen würden - dann kommts nach ein paar minuten zu ersten kollisionen mit duplicate keys, weil eben zwischen subselect und eigentlichem insert ein paar millisekunden liegen, in der ein zweiter client den subselect macht und dieselbe alte id kriegt wie der client vorher.

immerhin, die sache scheint es wert zu sein: postgresql steckt die vielen gleichzeitigen inserts und selects auf eine table mit weit weniger serverlast weg als mysql, selbst mit innodb-tables.

thomas

wenn du als id eine serial nimmst(tust du ja eh schon oder?)
dann kannst du dir das mit der manuellen eingabe sparen und dann sollte es auch keine probleme mit doppelten einträgen geben!

Crypi

Hallo Thomas

als mysql-umsteiger kann ich Dir nur mal empfehlen, die Doku von PostgreSQL zu lesen. In PostgreSQL gibt es Mechnismen, die es so unter MySQL nicht gibt.

Auch das Lesen von Artikel in diesen Forum ist angebracht. Viele Fragen betreffen nämlich Standdardprobleme. Und Dein Problem ist ein Standardproblem.

Wenn Du Dich beklagst, dass Du “grade den ganz bitteren weg” gehst, beruht das auf den vorher gesagten.

5 Artikel vor Deinem Artikel steht die Lösung:


CREATE TABLE a 
( 
id SERIAL PRIMARY KEY, 
a1 .... 
... 
);



BEGIN;
LOCK a;
INSERT INTO a (a1, …) VALUES (…);
COMMIT;

Damit bist Du auf der sicheren Seite. Die Feinheiten über die Befehle solltest Du in der DOKU nachlesen.



mfg

fristo

Fristo,

ja, ich gebe dir uneingeschränkt Recht: Lesen bildet, und ich habe das vorher zuwenig getan.

Für mich ist eine Datenbank eine Stelle, an die ich meine Records stopfe und nach Bedarf wieder raushole und ich möchte mich sowenig wie möglich drum kümmern müssen. Dass eine komplexere Datenbank auch komplexere Bedienung und erweitertes Wissen verlangt, erkenne ich zähneknirschend gerne an.

Gelobt sei der Tag, an dem ich mir einen DB-Admin leisten kann, der sich um die Optimierung der Datenhaltung kümmert.

Thomas

tag thomas

du kannst auch die ids aus deiner alten tabelle behalten, wenn du willst, auch mit einer sequenz.

dazu musst du nur den aktuellen wert der sequenz, nachdem du deine daten eingefügt hast auf den max(id) +1 wert setzen, denn sonst beginnt die sequenz wieder bei 1 und es gibt doppelte ids.

mfg
henrik

henrik,

lass dich küssen!
select setval(‘TABLENAME_id_seq’, 8200000);

hat alle probleme gelöst!

ts

Hallo Thomas,

Leider suggestiert die Werbung immer wieder, dass man mittels DRAG und DROP mal eben so seine Applikation zusammenbauen kann. In der Realität sieht das aber anders aus.

Ich kenne weder das Wissen noch die Erfahrung der hier Fragenden. Auch nicht, was ein Tool wie PostgreSQL in ihren Vorstellungen leisten soll. Aus den gemachten Angaben kann ich nur Rückschlüsse ziehen, und wenn da jemand schreibt, dass er bereits mit MySQL gearbeitet hat, setzte ich entsprechende Datenbankkenntnisse vorraus.

Dass das bei Dir nicht so ist, konnte ich vorher nicht ahnen und das ganze war auch nicht so negativ gemeint. Es sollte auch ein Ansporn sein, sich mal mit den Möglichkeiten, die PostgreSQL gegenüber MySql bietet, auseinder zu setzen.



mfg

fristo

ok, vielleicht habe ich untertrieben:
ich habe bis 2001 vier jahre lang für diverse computermagazine hauptberuflich komplexe webapplikationen und foren mit mysql- und sql-server-backend gebaut und administriert.

ich hab aber weder db-design noch sql jemals wirklich gelernt - ich komme nach wie vor ins schwitzen, wenn ich einen join über mehr als eine tabelle bauen soll.
mit mysql habe ich gelernt, dass man das auch gar nicht braucht, weil 3 selects nacheinander genausoschnell erledigt sind wie ein join. das ist so einfach wie drag und drop, so wie es die werbung sagt. wer mal ansatzweise von feldtypen, db-normalisierung und indexen gehoert hat, kann mit mysql oder access loslegen und wird so schnell keine probleme bekommen.

ich hatte nicht erwartet, dass mit postgresql alles einfach ist, aber dass ich mit einer applikation erstmal so auf die schnauze falle, war ich nicht mehr gewohnt!

immerhin, die tage des lesens und gruebelns scheinen sich rentiert zu haben - wo mysql bei 10 clients die grätsche machte, ist die LoadAverage bei postgres noch immer unter 1 und die datenbank richtig flott!

ich fürchte, ich habe noch eine reihe von “dummen” fragen, die einem sql-profi vermutlich die tränen in die augen treiben…

danke fuer die hilfe erstmal!

thomas

Es ergeht jeden so, der sich in ein neues Gebiet einarbeitet!



Dumme Fragen gibt es grundsätzlich nicht! Auch die Profis haben mal gelernt!



Aber nochmals zu Deiner Lösung. Ich glaube nicht, das sie einen Stresstest stand hält. Deshalb hier noch eine kleine Erklärung zum meinem Vorschlag.

LOCK sperrt den Zugriff auf die Tabelle, so das ein INSERT von anderen Klients zur gleichen Zeit nicht möglich ist.

COMMIT sorgt dafür, das Du nur gültige Datensätze einfügen kannst (und nicht nur das).

Der LOCK wird am Ende des COMMIT’s automatisch wieder aufgehoben.

Allerdings können Deine Klients Fehlermeldungen erhalten, die da besagen, dass ein Zugriff auf die Tabelle zur Zeit nicht möglich ist. Dann sollte der Klient die Daten nach einer bestimmten Verzögerungszeit nochmals an den Server senden.



mfg

fristo

wenn die db die primary-ids vergibt (das tut sie jetzt, dank Type=serial und korrekt gestzter SEQ), sollten auch gleichzeitige inserts problemlos sein.

eventuelle doppeleinträge werden durch uniqe-indizes abgefangen - das script kriegt dann eine fehlermeldung und von der db und gut iss, das kann ich aufgrund des geschwindigkeitsvorteils gegenüber einem exklusivem lock gut verschmerzen (das war ja eines der probleme bei mysql!) und es kommt für mich aufs selbe raus, ob der insert nicht funktioniert hat, weil die identischen daten schon da sind, oder ob eine transaktion aus diesem grund scheitert. (ja, ich weiss, alles eine stilfrage…)

ich habe im moment nur ein script, das nicht parallel laufen kann, und da denke ich im moment ernsthaft drüber nach, die queries dort in eine transaktion zu verpacken. mal sehen, wie sich das auf die performance auswirkt.

thomas