Autoincremento do PostgreSQL


579

Estou mudando do MySQL para o PostgreSQL e queria saber como posso fazer valores de incremento automático. Vi nos documentos do PostgreSQL um tipo de dados "serial", mas recebo erros de sintaxe ao usá-lo (na v8.0).


9
se você fornecer a consulta e o erro que está recebendo, talvez alguém possa lhe dizer o que há de errado com a consulta.

2
Meu primeiro hit também foi Mich 'e, como é uma pergunta que obtém visualizações suficientes para ser relevante, por que não votar? PS não é trivial se você não sabe como fazê-lo.
— precisa saber é o seguinte

1
SERIAL é a opção preferida se o driver do seu cliente for Npgsql. O provedor está selecionando internamente novos valores após um INSERT usando SELECT currval (pg_get_serial_sequence ('table', 'column')). Isto irá falhar se a coluna subjacente não é do tipo em série (tipo numérico explícito + sequência por exemplo)
— Olivier MATROT

Só por curiosidade ... Por que alguém precisa migrar do MySQL, o que é muito bom, para o PostgreSql?
— villamejia

17
... o que é ainda melhor.
— Rohmer 21/11

Respostas:


702

Sim, SERIAL é a função equivalente.

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 é apenas uma macro de tempo de criação de tabela em torno de seqüências. Você não pode alterar SERIAL em uma coluna existente.


19
citando o nome da tabela é uma prática muito ruim
— Evan Carroll

71
A citação dos nomes das tabelas é um hábito, pois herdei um banco de dados que tinha nomes de casos mistos e citar nomes de tabelas é um requisito de uso.
— Trey

26
@Evan Carroll - Por que é um mau hábito (apenas perguntando)?
— Christian

27
porque a menos que você tenha uma tabela "Table"e "table", em seguida, deixá-lo sem aspas e canonizar-lo para table. A convenção é simplesmente nunca usar aspas na pág. Você pode, se quiser, usar nomes mistos de maiúsculas e minúsculas para a aparência, apenas não é necessário: CREATE TABLE fooBar ( .. ); SELECT * FROM fooBar;funcionará da mesma forma SELECT * FROM foobar.
— Evan Carroll

26
Por documento do postgres, aspas ou aspas consistentes: postgresql.org/docs/current/interactive/…
— Καrτhικ

225

Você pode usar qualquer outro tipo de dados inteiro , como smallint.

Exemplo:

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;

Melhor usar seu próprio tipo de dados, em vez do tipo de dados seriais do usuário .


11
Eu diria que essa é realmente a melhor resposta, pois me permitiu modificar uma tabela que acabei de criar no PostgreSQL, definindo as colunas como padrão (depois de ler em CREATE SEQUENCE postgresql.org/docs/8.1/interactive/sql-createsequence.html ) . No entanto, não sei ao certo por que você mudou o proprietário.
— JayC

12
@ JayC: Da documentação : Por fim, a sequência é marcada como "de propriedade" da coluna, para que seja eliminada se a coluna ou tabela for eliminada.
— User272735 18/01/12

9
por que a comunidade postgres não reinventa a palavra-chave autoincrement?
— Dr Deo 27/05

2
@Dr Deo: eles usam série de palavras-chave em vez autoincrement, eu não sei por que :)
— Ahmad

4
Também existe uma série pequena, se você quiser apenas um tipo de dados menor.
— beldaz

110

Se você deseja adicionar uma sequência ao id na tabela que já existe, você pode usar:

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

O que é sequência? Onde fica AUTO_INCREMENT?
— Verde

23
@ Green: AUTO_INCREMENT não faz parte do padrão SQL, é específico ao MySQL. Sequências são algo que faz um trabalho semelhante no PostgreSQL.
— beldaz

5
se você usar 'id SERIAL', ele criará automaticamente uma sequência no PostgreSQL. Nome dessa sequência será <nome da tabela> _ <nome da coluna> _seq
— Jude Niroshan

Você não precisa usar ALTER COLUMN user_id?
— Alec

Eu tentei este método, mas recebo um erro: ERROR: syntax error at or near "DEFAULT"Alguma sugestão?
— Ely Fialkoff

44

Embora pareça que sequências equivalem ao auto_increment do MySQL, existem algumas diferenças sutis, mas importantes:

1. Consultas com falha incrementam a sequência / série

A coluna serial é incrementada em consultas com falha. Isso leva à fragmentação das consultas com falha, não apenas às exclusões de linha. Por exemplo, execute as seguintes consultas no banco de dados 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;

Você deve obter a seguinte saída:

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

Observe como o uid passa de 1 para 3 em vez de 1 para 2.

Isso ainda ocorre se você criar manualmente sua própria sequência com:

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;

Se você deseja testar como o MySQL é diferente, execute o seguinte em um banco de dados 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);

Você deve obter o seguinte sem fracionamento :

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

2. A configuração manual do valor da coluna serial pode causar falhas em futuras consultas.

Isso foi apontado pelo @trev em uma resposta anterior.

Para simular isso manualmente, defina o uid como 4, que entrará em conflito mais tarde.

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

Dados da tabela:

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

Execute outra inserção:

INSERT INTO table1 (col_b) VALUES(6);

Dados da tabela:

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

Agora, se você executar outra inserção:

INSERT INTO table1 (col_b) VALUES(7);

Ele falhará com a seguinte mensagem de erro:

ERRO: o valor duplicado da chave viola a restrição exclusiva "table1_pkey" DETALHE: A chave (uid) = (5) já existe.

Por outro lado, o MySQL lidará com isso normalmente, como mostrado abaixo:

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

Agora insira outra linha sem definir uid

INSERT INTO table1 (col_b) VALUES(3);

A consulta não falha, o uid apenas salta para 5:

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

O teste foi realizado no MySQL 5.6.33, para Linux (x86_64) e PostgreSQL 9.4.9


10
Você está fazendo uma comparação, mas não vejo nenhuma solução aqui! Isso é uma resposta?
— Anwar

4
@ Anwar simplesmente estende as várias respostas que afirmam que a resposta é usar uma série / sequência. Isso fornece um contexto importante a ser levado em consideração.
— Programster

38

A partir do Postgres 10, as colunas de identidade conforme definidas pelo padrão SQL também são suportadas:

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

cria uma coluna de identidade que não pode ser substituída, a menos que seja solicitado explicitamente. A inserção a seguir falhará com uma coluna definida como generated always:

insert into foo (id) 
values (1);

No entanto, isso pode ser anulado:

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

Ao usar a opção, generated by defaultesse é essencialmente o mesmo comportamento da serialimplementação existente :

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

Quando um valor é fornecido manualmente, a sequência subjacente também precisa ser ajustada manualmente - o mesmo que com uma serialcoluna.


Uma coluna de identidade não é uma chave primária por padrão (assim como uma serialcoluna). Se for um, uma restrição de chave primária precisa ser definida manualmente.


26

Desculpe, refazer uma pergunta antiga, mas essa foi a primeira pergunta / resposta do Stack Overflow que apareceu no Google.

Esta postagem (que surgiu pela primeira vez no Google) fala sobre o uso da sintaxe mais atualizada para o PostgreSQL 10: https://blog.2ndquadrant.com/postgresql-10-identity-columns/

que passa a ser:

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

Espero que ajude :)


1
Este é realmente o caminho a seguir no PostgreSQL 10 e é a mesma sintaxe que outros softwares de banco de dados como DB2 ou Oracle.
— adriaan

1
@adriaan Na verdade, os GENERATED … AS IDENTITYcomandos são SQL padrão. Primeiro adicionado no SQL: 2003 , depois esclarecido no SQL: 2008 . Veja os recursos # T174 e F386 e T178.
— Basil Bourque

16

Você deve ter cuidado para não inserir diretamente em seu campo SERIAL ou sequência, caso contrário, sua gravação falhará quando a sequência atingir o valor inserido:

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

No contexto da pergunta feita e em resposta ao comentário de @ sereja1c, criar SERIALimplicitamente cria sequências, portanto, para o exemplo acima,

CREATE TABLE foo (id SERIAL,bar varchar);

CREATE TABLEcriaria implicitamente sequência foo_id_seqpara a coluna serial foo.id. Portanto, SERIAL[4 bytes] é bom por sua facilidade de uso, a menos que você precise de um tipo de dados específico para seu ID.


3

Desta forma, irá funcionar com certeza, espero que ajude:

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');

Você pode verificar isso nos detalhes no próximo link: http://www.postgresqltutorial.com/postgresql-serial/


3

Desde o PostgreSQL 10

CREATE TABLE test_new (
    id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    payload text
);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.