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).
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.
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 .
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');
Obwohl es so aussieht, als wären Sequenzen das Äquivalent zu MySQL auto_increment, gibt es einige subtile, aber wichtige Unterschiede:
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)
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
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.
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 :)
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;
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.
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/
Seit PostgreSQL 10
CREATE TABLE test_new (
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
payload text
);