PostgreSQL Автоинкремент

492

Я перехожу из MySQL в PostgreSQL и задаюсь вопросом, как я могу делать значения автоинкремента. Я видел в документах PostgreSQL тип данных "serial", но я получаю синтаксические ошибки при его использовании (в версии 4.0).

  • 8
    если вы предоставите запрос и полученную ошибку - возможно, кто-то скажет вам, что не так с запросом.
  • 2
    Мой первый хит тоже Mich ', и, поскольку это вопрос, который получает достаточно мнений, чтобы быть актуальным, почему бы не проголосовать. PS Это не тривиально, если вы не знаете, как это сделать.
Показать ещё 3 комментария
Теги:
auto-increment

10 ответов

681
Лучший ответ

Да, 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 на существующий столбец.

  • 0
    С какой версии можно найти этот тип данных? Я использую sequence.nextval в pgsql, потому что я не заметил ничего подобного. Благодарю.
  • 2
    по его словам, это просто макрос вокруг последовательностей. тип SERIAL - это просто целое число и последовательность, в которой по умолчанию для столбца задано следующее значение последовательности. В отличие от MySQL, в этом нет ничего особенного и вудуного.
Показать ещё 14 комментариев
223

Вы можете использовать любой другой целочисленный тип данных, например 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;

Лучше использовать свой собственный тип данных, а не пользователь серийный тип данных.

  • 10
    Я бы сказал, что это на самом деле лучший ответ, потому что он позволил мне изменить таблицу, которую я только что создал в PostgreSQL, установив столбцы по умолчанию (после прочтения на CREATE SEQUENCE postgresql.org/docs/8.1/interactive/sql-createsequence. HTML ). ОДНАКО, я не совсем уверен, почему вы сменили владельца.
  • 11
    @JayC: Из документации : Наконец, последовательность помечается как «принадлежащая» столбцу, так что она будет отброшена, если столбец или таблица будут удалены.
Показать ещё 6 комментариев
88

Если вы хотите добавить последовательность в id в уже существующую таблицу, вы можете использовать:

CREATE SEQUENCE user_id_seq;
ALTER TABLE user ALTER user_id SET DEFAULT NEXTVAL('user_id_seq');
  • 0
    Что такое последовательность? Где находится AUTO_INCREMENT?
  • 21
    @Green: AUTO_INCREMENT не является частью стандарта SQL, он специфичен для MySQL. Последовательности - это то, что выполняет аналогичную работу в PostgreSQL.
Показать ещё 3 комментария
40

Хотя похоже, что последовательности являются эквивалентом MySQL auto_increment, есть некоторые тонкие, но важные отличия:

1. Неудачные запросы Приращение Последовательность/Серийный

Серийный столбец увеличивается при неудачных запросах. Это приводит к фрагментации из неудавшихся запросов, а не к удалению строк. Например, запустите следующие запросы в базе данных 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)

2. Вручную установка значения Serial Column может привести к сбою будущих запросов.

Это было указано в предыдущем ответе @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" ДЕТАЛИ: Key (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

  • 7
    Вы даете сравнение, но я не вижу здесь никакого решения! Это ответ?
  • 3
    @ Анвара просто расширяет различные ответы, в которых говорится, что ответ должен использовать сериал / последовательность. Это обеспечивает некоторый важный контекст, который необходимо учитывать.
31

Начиная с 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). Если это должно быть одно, ограничение первичного ключа должно быть определено вручную.

19

Извините, перефразирую старый вопрос, но это был первый вопрос/ответ о переполнении стека, который появился в 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,
);

Надеюсь, это поможет :)

  • 1
    Это действительно путь в PostgreSQL 10 и тот же синтаксис, что и в других программах баз данных, таких как DB2 или Oracle.
  • 1
    это помогло спасибо
Показать ещё 1 комментарий
16

Вы должны быть осторожны, чтобы не вставлять их непосредственно в поле SERIAL или последовательности, иначе ваша запись не сработает, когда последовательность достигнет вставленного значения:

-- 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; 
15

В контексте заданного вопроса и в ответ на комментарий by @sereja1c создание SERIAL неявно создает последовательности, поэтому для приведенного выше примера -

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLE будет неявно создавать последовательность foo_id_seq для последовательного столбца foo.id. Следовательно, SERIAL [4 байта] хорош для удобства использования, если вам не нужен определенный тип данных для вашего идентификатора.

2

Этот способ будет работать наверняка, надеюсь, он поможет:

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/

0

Начиная с PostgreSQL 10

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню