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

Ian
fonte
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.

Trey
fonte
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 .

Ahmad
fonte
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');
sereja
fonte
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

Programador
fonte
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.

um cavalo sem nome
fonte
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 :)

Zhao Li
fonte
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; 
trev
fonte
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.

Principe
fonte
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/

webtechnelson
fonte
3

Desde o PostgreSQL 10

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