it-swarm.com.de

PostgreSQL Autoincrement

Ich bin von MySQL zu PostgreSQL gewechselt und habe mich gefragt, wie ich Autoincrement-Werte durchführen kann. Ich habe in den PostgreSQL-Dokumenten einen Datentyp "serial" gesehen, aber ich bekomme Syntaxfehler, wenn ich ihn verwende (in v8.0).

544
Ian

Ja, SERIAL ist die entsprechende Funktion.

CREATE TABLE foo (
id SERIAL,
bar varchar);

INSERT INTO foo (bar) values ('blah');
INSERT INTO foo (bar) values ('blah');

SELECT * FROM foo;

1,blah
2,blah

SERIAL ist nur ein Makro zum Erstellen von Tabellenzeiten um Sequenzen. Sie können SERIAL nicht für eine vorhandene Spalte ändern.

669
Trey

Sie können jeden anderen Integer-Datentyp verwenden, z. B. smallint.

Beispiel

CREATE SEQUENCE user_id_seq;
CREATE TABLE user (
    user_id smallint NOT NULL DEFAULT nextval('user_id_seq')
);
ALTER SEQUENCE user_id_seq OWNED BY user.user_id;

Verwenden Sie lieber Ihren eigenen Datentyp als user serieller Datentyp .

217
Ahmad

Wenn Sie der ID in der bereits vorhandenen Tabelle eine Sequenz hinzufügen möchten, können Sie Folgendes verwenden:

CREATE SEQUENCE user_id_seq;
ALTER TABLE user ALTER user_id SET DEFAULT NEXTVAL('user_id_seq');
98
sereja

Obwohl es so aussieht, als wären Sequenzen das Äquivalent zu MySQL auto_increment, gibt es einige subtile, aber wichtige Unterschiede:

1. Fehlgeschlagene Abfragen erhöhen die Sequenz/Seriennummer

Die serielle Spalte wird bei fehlgeschlagenen Abfragen erhöht. Dies führt zu einer Fragmentierung aufgrund fehlgeschlagener Abfragen und nicht nur zu Zeilenlöschungen. Führen Sie beispielsweise die folgenden Abfragen in Ihrer PostgreSQL-Datenbank aus:

CREATE TABLE table1 (
  uid serial NOT NULL PRIMARY KEY,
  col_b integer NOT NULL,
  CHECK (col_b>=0)
);

INSERT INTO table1 (col_b) VALUES(1);
INSERT INTO table1 (col_b) VALUES(-1);
INSERT INTO table1 (col_b) VALUES(2);

SELECT * FROM table1;

Sie sollten die folgende Ausgabe erhalten:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
(2 rows)

Beachten Sie, wie uid von 1 nach 3 anstatt von 1 nach 2 wechselt.

Dies tritt immer noch auf, wenn Sie Ihre eigene Sequenz manuell erstellen:

CREATE SEQUENCE table1_seq;
CREATE TABLE table1 (
    col_a smallint NOT NULL DEFAULT nextval('table1_seq'),
    col_b integer NOT NULL,
    CHECK (col_b>=0)
);
ALTER SEQUENCE table1_seq OWNED BY table1.col_a;

Wenn Sie testen möchten, wie sich MySQL unterscheidet, führen Sie Folgendes in einer MySQL-Datenbank aus:

CREATE TABLE table1 (
  uid int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  col_b int unsigned NOT NULL
);

INSERT INTO table1 (col_b) VALUES(1);
INSERT INTO table1 (col_b) VALUES(-1);
INSERT INTO table1 (col_b) VALUES(2);

Sie sollten folgendes mit ohne Frustration erhalten:

+-----+-------+
| uid | col_b |
+-----+-------+
|   1 |     1 |
|   2 |     2 |
+-----+-------+
2 rows in set (0.00 sec)

2. Das manuelle Festlegen des Werts für die serielle Spalte kann dazu führen, dass zukünftige Abfragen fehlschlagen.

Dies wurde von @trev in einer früheren Antwort darauf hingewiesen.

Um dies manuell zu simulieren, setzen Sie die UID auf 4, was später "zusammenstößt".

INSERT INTO table1 (uid, col_b) VALUES(5, 5);

Tabellendaten:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
   5 |     5
(3 rows)

Führen Sie eine weitere Einfügung aus:

INSERT INTO table1 (col_b) VALUES(6);

Tabellendaten:

 uid | col_b 
-----+-------
   1 |     1
   3 |     2
   5 |     5
   4 |     6

Wenn Sie jetzt eine andere Einfügung ausführen:

INSERT INTO table1 (col_b) VALUES(7);

Es wird mit der folgenden Fehlermeldung fehlschlagen:

FEHLER: doppelter Schlüsselwert verletzt eindeutige Bedingung "table1_pkey" DETAIL: Schlüssel (uid) = (5) ist bereits vorhanden.

Im Gegensatz dazu wird MySQL wie folgt ordnungsgemäß damit umgehen:

INSERT INTO table1 (uid, col_b) VALUES(4, 4);

Fügen Sie nun eine weitere Zeile ein, ohne die UID einzustellen

INSERT INTO table1 (col_b) VALUES(3);

Die Abfrage schlägt nicht fehl, UID springt nur zu 5:

+-----+-------+
| uid | col_b |
+-----+-------+
|   1 |     1 |
|   2 |     2 |
|   4 |     4 |
|   5 |     3 |
+-----+-------+

Die Tests wurden unter MySQL 5.6.33 für Linux (x86_64) und PostgreSQL 9.4.9 durchgeführt

39
Programster

Ab Postgres 10 werden auch Identitätsspalten gemäß dem SQL-Standard unterstützt:

create table foo 
(
  id integer generated always as identity
);

erstellt eine Identitätsspalte, die nur dann überschrieben werden kann, wenn Sie ausdrücklich dazu aufgefordert werden. Die folgende Einfügung schlägt mit einer als generated always definierten Spalte fehl:

insert into foo (id) 
values (1);

Dies kann jedoch außer Kraft gesetzt werden:

insert into foo (id) overriding system value 
values (1);

Bei Verwendung der Option generated by default ist dies im Wesentlichen dasselbe Verhalten wie bei der vorhandenen serial -Implementierung:

create table foo 
(
  id integer generated by default as identity
);

Wenn ein Wert manuell eingegeben wird, muss die zugrunde liegende Sequenz ebenfalls manuell angepasst werden - genau wie bei einer serial -Spalte.


Eine Identitätsspalte ist standardmäßig kein Primärschlüssel (genau wie eine serial -Spalte). Sollte dies der Fall sein, muss eine Primärschlüsselbedingung manuell definiert werden.

35

Entschuldigung, um eine alte Frage noch einmal aufzuwärmen, aber dies war die erste Stapelüberlauf-Frage/Antwort, die bei Google aufgetaucht ist.

In diesem Beitrag (der zuerst bei Google veröffentlicht wurde) geht es um die Verwendung der aktuelleren Syntax für PostgreSQL 10: https://blog.2ndquadrant.com/postgresql-10-identity-columns/

was ist zufällig:

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
);

Ich hoffe, das hilft :)

21
A L

Sie müssen darauf achten, nicht direkt in Ihr SERIAL- oder Sequenzfeld einzufügen, sonst schlägt das Schreiben fehl, wenn die Sequenz den eingegebenen Wert erreicht:

-- Table: "test"

-- DROP TABLE test;

CREATE TABLE test
(
  "ID" SERIAL,
  "Rank" integer NOT NULL,
  "GermanHeadword" "text" [] NOT NULL,
  "PartOfSpeech" "text" NOT NULL,
  "ExampleSentence" "text" NOT NULL,
  "EnglishGloss" "text"[] NOT NULL,
  CONSTRAINT "PKey" PRIMARY KEY ("ID", "Rank")
)
WITH (
  OIDS=FALSE
);
-- ALTER TABLE test OWNER TO postgres;
 INSERT INTO test("Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (1, '{"der", "die", "das", "den", "dem", "des"}', 'art', 'Der Mann küsst die Frau und das Kind schaut zu', '{"the", "of the" }');


 INSERT INTO test("ID", "Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (2, 1, '{"der", "die", "das"}', 'pron', 'Das ist mein Fahrrad', '{"that", "those"}');

 INSERT INTO test("Rank", "GermanHeadword", "PartOfSpeech", "ExampleSentence", "EnglishGloss")
           VALUES (1, '{"der", "die", "das"}', 'pron', 'Die Frau, die nebenen wohnt, heißt Renate', '{"that", "who"}');

SELECT * from test; 
16
trev

Im Kontext der gestellten Frage und als Antwort auf den Kommentar von @ sereja1c werden beim Erstellen von SERIAL implizit Sequenzen erstellt.

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLE würde implizit die Sequenz foo_id_seq für die serielle Spalte foo.id erstellen. Daher ist SERIAL [4 Bytes] für die Benutzerfreundlichkeit gut, es sei denn, Sie benötigen einen bestimmten Datentyp für Ihre ID.

15
Prince

Dieser Weg wird sicher funktionieren, ich hoffe, es hilft:

CREATE TABLE fruits(
   id SERIAL PRIMARY KEY,
   name VARCHAR NOT NULL
);

INSERT INTO fruits(id,name) VALUES(DEFAULT,'Apple');

or

INSERT INTO fruits VALUES(DEFAULT,'Apple');

Sie können dies die Details im nächsten Link überprüfen: http://www.postgresqltutorial.com/postgresql-serial/

2
webtechnelson

Seit PostgreSQL 10

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    payload text
);