Como adicionar uma chave primária de incremento automático a uma tabela existente, no PostgreSQL?

190

Eu tenho uma tabela com dados existentes. Existe uma maneira de adicionar uma chave primária sem excluir e recriar a tabela?

xRobot
fonte

Respostas:

355

( Atualizado - Obrigado às pessoas que comentaram )

Versões modernas do PostgreSQL

Suponha que você tenha uma tabela chamada test1, à qual deseja adicionar uma idcoluna de chave primária (substituto) de incremento automático . O seguinte comando deve ser suficiente nas versões recentes do PostgreSQL:

   ALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;

Versões anteriores do PostgreSQL

Nas versões antigas do PostgreSQL (anteriores à 8.x?), Você tinha que fazer todo o trabalho sujo. A seguinte sequência de comandos deve fazer o truque:

  ALTER TABLE test1 ADD COLUMN id INTEGER;
  CREATE SEQUENCE test_id_seq OWNED BY test1.id;
  ALTER TABLE test ALTER COLUMN id SET DEFAULT nextval('test_id_seq');
  UPDATE test1 SET id = nextval('test_id_seq');

Novamente, nas versões recentes do Postgres, isso é aproximadamente equivalente ao comando único acima.

leonbloy
fonte
3
Estou usando o ORACLE, portanto, compartilhá-lo pode ser útil para os funcionários do ORACLE No ORACLE: ALTER TABLE TEST1 ADD ID NUMBER; UPDATE TEST1 SET ID = TEST1_SEQ.NEXTVAL; ALTER TABLE TEST1 ADICIONAR CHAVE PRIMÁRIA (ID); criar um TEST1_SEQ Sequence antes de executar instrução UPDATE
msbyuva
Observe que ADD PRIMARY KEYtambém cria uma NOT NULLrestrição (testada no postgres 9.3) conforme o esperado e desejado.
Jared Beck
19
No Postgres, você pode usar um único comandoALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;
resnyanskiy 20/02/2015
1
Além do comentário de @ resnyanskiy, isso funcionará mesmo quando houver dados na tabela. Os IDs são preenchidos e a restrição não nula é definida. A resposta inteira pode ser substituída pela linha desse comentário.
Synesso
1
@ EricWang Obrigado, Eric, você está certo - acredito que isso não funcionou há algumas versões (anos) atrás, mas não tenho certeza. Transformou a resposta em community-wiki.
Leonbloy 16/05
57
ALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;

É tudo o que você precisa:

  1. Adicione o id coluna
  2. Preencha-o com uma sequência de 1 a contagem (*).
  3. Defina como chave primária / não nula.

É dado crédito a @resnyanskiy, que deu essa resposta em um comentário.

Synesso
fonte
2
Este deve ser marcado como resposta, ea resposta deve pertencer a @resnyanskiy
Eric Wang
Eu tive que primeiro largar o pkey e depois executar isso. ALTER TABLE <table> DROP CONSTRAINT <pkey_name>;
Josh Robertson
10

Para usar uma coluna de identidade na v10,

ALTER TABLE test 
ADD COLUMN id { int | bigint | smallint}
GENERATED { BY DEFAULT | ALWAYS } AS IDENTITY PRIMARY KEY;

Para obter uma explicação das colunas de identidade, consulte https://blog.2ndquadrant.com/postgresql-10-identity-columns/ .

Para a diferença entre GERADO POR PADRÃO e GERADO SEMPRE, consulte https://www.cybertec-postgresql.com/en/sequences-gains-and-pitfalls/ .

Para alterar a sequência, consulte https://popsql.io/learn-sql/postgresql/how-to-alter-sequence-in-postgresql/ .

jhoanna
fonte
O problema com esta solução é que, se a tabela já contém linhas, você recebe um erro:SQL Error [23502]: ERROR: column "id" contains null values
isapir
3
@isapir: Houve um erro nas versões anteriores (páginas 10 e 10.1) produzindo esse erro. Foi corrigido com a página 10.2. Detalhes aqui: dba.stackexchange.com/q/200143/3684
Erwin Brandstetter
Obrigado @ erwin-brandstetter
isapir
Um ano mais tarde eu encontrei esta resposta novamente, erro aparentemente fixo, upvoted;)
isapir
2

Eu cheguei aqui porque estava procurando por algo assim também. No meu caso, eu estava copiando os dados de um conjunto de tabelas temporárias com muitas colunas em uma tabela e também atribuindo IDs de linha à tabela de destino. Aqui está uma variante das abordagens acima que eu usei. Eu adicionei a coluna serial no final da minha tabela de destino. Dessa forma, não preciso ter um espaço reservado para ele na instrução Insert. Em seguida, uma simples seleção * na tabela de destino preencheu automaticamente esta coluna. Aqui estão as duas instruções SQL que eu usei no PostgreSQL 9.6.4.

ALTER TABLE target ADD COLUMN some_column SERIAL;
INSERT INTO target SELECT * from source;
Dean Sha
fonte