Przechodzę z MySQL na PostgreSQL i zastanawiałem się, jak mogę wykonać automatyczne zwiększenie wartości. W dokumentach PostgreSQL widziałem typ danych „seryjny”, ale podczas korzystania z niego występują błędy składniowe (w wersji 8.0).
Przechodzę z MySQL na PostgreSQL i zastanawiałem się, jak mogę wykonać automatyczne zwiększenie wartości. W dokumentach PostgreSQL widziałem typ danych „seryjny”, ale podczas korzystania z niego występują błędy składniowe (w wersji 8.0).
Odpowiedzi:
Tak, SERIAL jest równoważną funkcją.
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 to po prostu makro czasu tabeli wokół sekwencji. Nie możesz zmienić SERIAL na istniejącą kolumnę.
"Table"
a "table"
następnie po prostu zostaw go nie cytowany i kanonizuj go table
. Konwencja po prostu nigdy nie używa cudzysłowów w Pg. Możesz, jeśli chcesz, używać różnych nazw liter do wyglądu, po prostu nie wymagaj tego: CREATE TABLE fooBar ( .. ); SELECT * FROM fooBar;
będzie działać, jak będzie SELECT * FROM foobar
.
Możesz użyć dowolnego innego typu danych całkowitych , takiego jak smallint
.
Przykład:
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;
Lepiej jest używać własnego typu danych niż szeregowego typu danych użytkownika .
CREATE SEQUENCE
postgresql.org/docs/8.1/interactive/sql-createsequence.html ) . JEDNAK nie jestem pewien, dlaczego zmieniłeś właściciela.
Jeśli chcesz dodać sekwencję do identyfikatora w tabeli, która już istnieje, możesz użyć:
CREATE SEQUENCE user_id_seq;
ALTER TABLE user ALTER user_id SET DEFAULT NEXTVAL('user_id_seq');
ALTER COLUMN user_id
?
ERROR: syntax error at or near "DEFAULT"
jakieś sugestie?
Choć wygląda na to, że sekwencje są odpowiednikiem auto_increment MySQL, istnieją pewne subtelne, ale ważne różnice:
Kolumna szeregowa jest zwiększana w przypadku nieudanych zapytań. Prowadzi to do fragmentacji z powodu nieudanych zapytań, a nie tylko usuwania wierszy. Na przykład uruchom następujące zapytania w bazie danych PostgreSQL:
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;
Powinieneś otrzymać następujące dane wyjściowe:
uid | col_b
-----+-------
1 | 1
3 | 2
(2 rows)
Zauważ, jak uid zmienia się z 1 na 3 zamiast 1 na 2.
Dzieje się tak nadal, jeśli ręcznie utworzysz własną sekwencję za pomocą:
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;
Jeśli chcesz przetestować, jak różni się MySQL, uruchom następujące polecenie w bazie danych MySQL:
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);
Powinieneś otrzymać następujące bez frustracji :
+-----+-------+
| uid | col_b |
+-----+-------+
| 1 | 1 |
| 2 | 2 |
+-----+-------+
2 rows in set (0.00 sec)
Zwrócił na to uwagę @trev w poprzedniej odpowiedzi.
Aby to zasymulować ręcznie, ustaw UID na 4, który później „zderzy się”.
INSERT INTO table1 (uid, col_b) VALUES(5, 5);
Dane tabeli:
uid | col_b
-----+-------
1 | 1
3 | 2
5 | 5
(3 rows)
Uruchom kolejną wkładkę:
INSERT INTO table1 (col_b) VALUES(6);
Dane tabeli:
uid | col_b
-----+-------
1 | 1
3 | 2
5 | 5
4 | 6
Teraz, jeśli uruchomisz inną wstawkę:
INSERT INTO table1 (col_b) VALUES(7);
Nie powiedzie się z następującym komunikatem o błędzie:
BŁĄD: zduplikowana wartość klucza narusza unikalne ograniczenie „table1_pkey” SZCZEGÓŁY: Klucz (UID) = (5) już istnieje.
W przeciwieństwie do tego MySQL poradzi sobie z tym z wdziękiem, jak pokazano poniżej:
INSERT INTO table1 (uid, col_b) VALUES(4, 4);
Teraz wstaw kolejny wiersz bez ustawiania UID
INSERT INTO table1 (col_b) VALUES(3);
Zapytanie nie kończy się niepowodzeniem, UID po prostu przeskakuje do 5:
+-----+-------+
| uid | col_b |
+-----+-------+
| 1 | 1 |
| 2 | 2 |
| 4 | 4 |
| 5 | 3 |
+-----+-------+
Testy przeprowadzono na MySQL 5.6.33, dla Linuksa (x86_64) i PostgreSQL 9.4.9
Począwszy od Postgres 10, obsługiwane są również kolumny tożsamości zdefiniowane w standardzie SQL:
create table foo
(
id integer generated always as identity
);
tworzy kolumnę tożsamości, której nie można zastąpić, chyba że zostanie o to wyraźnie poproszony. Następująca wstawka zakończy się niepowodzeniem z kolumną zdefiniowaną jako generated always
:
insert into foo (id)
values (1);
Można to jednak zmienić:
insert into foo (id) overriding system value
values (1);
Podczas korzystania z opcji generated by default
jest to zasadniczo to samo zachowanie, co istniejąca serial
implementacja:
create table foo
(
id integer generated by default as identity
);
Gdy wartość jest podawana ręcznie, sekwencję podstawową należy również dostosować ręcznie - tak samo jak w przypadku serial
kolumny.
Kolumna tożsamości nie jest domyślnie kluczem podstawowym (podobnie jak serial
kolumna). Jeśli ma to być jeden, ograniczenie klucza podstawowego należy zdefiniować ręcznie.
Przykro mi, aby powtórzyć stare pytanie, ale było to pierwsze pytanie / odpowiedź Przepełnienie stosu, które pojawiło się w Google.
Ten post (który pojawił się jako pierwszy w Google) mówi o używaniu bardziej zaktualizowanej składni PostgreSQL 10: https://blog.2ndquadrant.com/postgresql-10-identity-columns/
co się dzieje:
CREATE TABLE test_new (
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
);
Mam nadzieję, że to pomoże :)
GENERATED … AS IDENTITY
polecenia są standardowym SQL. Najpierw dodano w SQL: 2003 , a następnie wyjaśniono w SQL: 2008 . Zobacz funkcje # T174 i F386 i T178.
Musisz uważać, aby nie wstawić bezpośrednio do pola SERIAL lub sekwencji, w przeciwnym razie zapis nie powiedzie się, gdy sekwencja osiągnie wstawioną wartość:
-- 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;
W kontekście zadanego pytania i odpowiedzi na komentarz @ sereja1c, tworzenie SERIAL
niejawnie tworzy sekwencje, więc w powyższym przykładzie-
CREATE TABLE foo (id SERIAL,bar varchar);
CREATE TABLE
tworzyłoby domyślnie sekwencję foo_id_seq
dla kolumny szeregowej foo.id
. Dlatego SERIAL
[4 bajty] jest dobry ze względu na łatwość użycia, chyba że potrzebujesz określonego typu danych dla swojego identyfikatora.
Ten sposób na pewno zadziała, mam nadzieję, że pomoże:
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');
Możesz to sprawdzić szczegóły w następnym linku: http://www.postgresqltutorial.com/postgresql-serial/
Od PostgreSQL 10
CREATE TABLE test_new (
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
payload text
);