Я переключаюсь с MySQL на PostgreSQL и мне было интересно, как я могу делать автоинкрементные значения. В документации PostgreSQL я видел тип данных "serial", но при его использовании я получаю синтаксические ошибки (в v8.0).
Я переключаюсь с MySQL на PostgreSQL и мне было интересно, как я могу делать автоинкрементные значения. В документации PostgreSQL я видел тип данных "serial", но при его использовании я получаю синтаксические ошибки (в v8.0).
Ответы:
Да, SERIAL - эквивалентная функция.
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 - это просто макрос создания табличного времени вокруг последовательностей. Вы не можете изменить SERIAL на существующий столбец.
"Table"
а "table"
затем просто оставить его без кавычек и канонизировать его table
. Соглашение просто никогда не использовать кавычки в Pg. Вы можете, если хотите, использовать смешанные имена падежей для внешнего вида, просто не требуйте этого: CREATE TABLE fooBar ( .. ); SELECT * FROM fooBar;
будет работать, как и будет SELECT * FROM foobar
.
Вы можете использовать любой другой тип целочисленных данных , например smallint
.
Пример :
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;
Лучше использовать свой собственный тип данных, а не пользовательский серийный тип данных .
CREATE SEQUENCE
postgresql.org/docs/8.1/interactive/sql-createsequence.html ). , ОДНАКО, я не совсем уверен, почему вы сменили владельца.
Если вы хотите добавить последовательность к идентификатору в таблице, которая уже существует, вы можете использовать:
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"
какие-либо предложения?
Хотя похоже, что последовательности эквивалентны MySQL auto_increment, есть некоторые тонкие, но важные различия:
Последовательный столбец увеличивается при неудачных запросах. Это приводит к фрагментации неудачных запросов, а не просто к удалению строк. Например, выполните следующие запросы в вашей базе данных 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;
Вы должны получить следующий вывод:
uid | col_b
-----+-------
1 | 1
3 | 2
(2 rows)
Обратите внимание, как uid идет от 1 до 3 вместо 1 до 2.
Это все еще происходит, если вы должны были вручную создать свою собственную последовательность с:
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;
Если вы хотите проверить, как MySQL отличается, запустите следующее для базы данных 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);
Вы должны получить следующее без утомления :
+-----+-------+
| uid | col_b |
+-----+-------+
| 1 | 1 |
| 2 | 2 |
+-----+-------+
2 rows in set (0.00 sec)
Это было указано @trev в предыдущем ответе.
Чтобы смоделировать это вручную, установите для uid значение 4, которое позже будет «конфликтовать».
INSERT INTO table1 (uid, col_b) VALUES(5, 5);
Данные таблицы:
uid | col_b
-----+-------
1 | 1
3 | 2
5 | 5
(3 rows)
Запустите еще одну вставку:
INSERT INTO table1 (col_b) VALUES(6);
Данные таблицы:
uid | col_b
-----+-------
1 | 1
3 | 2
5 | 5
4 | 6
Теперь, если вы запустите другую вставку:
INSERT INTO table1 (col_b) VALUES(7);
Сбой со следующим сообщением об ошибке:
ОШИБКА: значение дублированного ключа нарушает уникальное ограничение "table1_pkey". ПОДРОБНЕЕ: Ключ (uid) = (5) уже существует.
Напротив, MySQL будет обрабатывать это изящно, как показано ниже:
INSERT INTO table1 (uid, col_b) VALUES(4, 4);
Теперь вставьте другую строку без установки UID
INSERT INTO table1 (col_b) VALUES(3);
Запрос не сбоит, uid просто переходит на 5:
+-----+-------+
| uid | col_b |
+-----+-------+
| 1 | 1 |
| 2 | 2 |
| 4 | 4 |
| 5 | 3 |
+-----+-------+
Тестирование проводилось на MySQL 5.6.33, для Linux (x86_64) и PostgreSQL 9.4.9.
Начиная с Postgres 10, также поддерживаются столбцы идентификаторов, определенные стандартом SQL:
create table foo
(
id integer generated always as identity
);
создает столбец идентификаторов, который не может быть переопределен без явного запроса. Следующая вставка завершится ошибкой со столбцом, определенным как generated always
:
insert into foo (id)
values (1);
Однако это может быть отменено:
insert into foo (id) overriding system value
values (1);
При использовании опции generated by default
это, по сути, то же поведение, что и существующая serial
реализация:
create table foo
(
id integer generated by default as identity
);
Когда значение вводится вручную, базовая последовательность также должна быть скорректирована вручную - так же, как для serial
столбца.
Столбец идентификации не является первичным ключом по умолчанию (как serial
столбец). Если это так, ограничение первичного ключа необходимо определить вручную.
Извините, перефразирую старый вопрос, но это был первый вопрос / ответ о переполнении стека, который появился в Google.
В этом посте (который впервые появился в Google) рассказывается об использовании более обновленного синтаксиса для PostgreSQL 10: https://blog.2ndquadrant.com/postgresql-10-identity-columns/
что бывает:
CREATE TABLE test_new (
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
);
Надеюсь, это поможет :)
GENERATED … AS IDENTITY
команды являются стандартным SQL. Сначала добавлено в SQL: 2003 , затем уточнено в SQL: 2008 . Смотрите особенности # T174 & F386 & T178.
Вы должны быть осторожны, чтобы не вставить непосредственно в поле SERIAL или sequence, иначе ваша запись не будет выполнена, когда последовательность достигнет вставленного значения:
-- 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;
В контексте заданного вопроса и в ответ на комментарий @ sereja1c создание SERIAL
неявно создает последовательности, поэтому для приведенного выше примера:
CREATE TABLE foo (id SERIAL,bar varchar);
CREATE TABLE
будет неявно создавать последовательность foo_id_seq
для последовательного столбца foo.id
. Следовательно, SERIAL
[4 байта] хороша для простоты использования, если вам не нужен конкретный тип данных для вашего идентификатора.
Этот способ будет работать наверняка, надеюсь, он поможет:
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');
Вы можете проверить это в следующей ссылке: http://www.postgresqltutorial.com/postgresql-serial/
Начиная с PostgreSQL 10
CREATE TABLE test_new (
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
payload text
);