Como altero a posição de uma coluna em uma tabela de banco de dados PostgreSQL?

Respostas:

107

" Alterar a posição da coluna " no PostgreSQL Wiki diz:

O PostgreSQL atualmente define a ordem das colunas com base na attnumcoluna da pg_attributetabela. A única maneira de alterar a ordem das colunas é recriar a tabela ou adicionar colunas e girar os dados até atingir o layout desejado.

Isso é muito fraco, mas em sua defesa, no SQL padrão, também não há solução para reposicionar uma coluna. As marcas de banco de dados que oferecem suporte à alteração da posição ordinal de uma coluna estão definindo uma extensão para a sintaxe SQL.

Outra ideia me ocorre: você pode definir um VIEWque especifica a ordem das colunas como você gosta, sem alterar a posição física da coluna na tabela base.

Bill Karwin
fonte
3
@Dana: Acho que é isso o que significa "recriar a mesa" no artigo wiki.
Bill Karwin
2
'despejar o banco de dados': ótima maneira de danificar dados. e, portanto, o efeito "limpar o banco de dados massivo".
Kent Fredric
31
@Kent: Duvidoso, os desenvolvedores do postgres percorrem um longo caminho para garantir a consistência dos dados e isso certamente se aplicaria ao pg_dump. Afinal, de que adianta fazer backups db se a restauração for interrompida?
Dana the Sane
@Dana, sim, mas você está adicionando 1) um grande processo para despejar, e então você descarta, e então você tem uma carga que consome muito tempo. Se você tiver um banco de dados muito grande, o que geralmente é o caso com 37 colunas, terá riscos de bloqueio de E / S de disco.
Kent Fredric
@DanatheSane estes são super antigos comentários, mas o que Bill estava dizendo é essencialmente a mesma coisa, em vez de fazer um despejo de banco de dados completo, você simplesmente despejar a mesa (e dependências), matar o original, em seguida, recriar. Não há necessidade de colocar todo o banco de dados offline ou perder tempo recriando algo que não seja afetado. Por outro lado, se houver muitas dependências, descobri que fazer um dump completo (como você sugeriu) é muito mais fácil.
vol7ron
37

No PostgreSQL, ao adicionar um campo, ele seria adicionado no final da tabela. Se precisarmos inserir em uma posição particular, então

alter table tablename rename to oldtable;
create table tablename (column defs go here);
insert into tablename (col1, col2, col3) select col1, col2, col3 from oldtable;
Todos ganham
fonte
4
Uau, isso é ótimo, tenho certeza que essa deve ser a resposta aceita!
Tommaso Thea Cioni
Sim, é muito útil, muito obrigado!
Acuna
Você também pode copiar a tabela atual para uma nova tabela antiga como este: CREATE TABLE tabela antiga AS SELECT * FROM nome da tabela;
Ryan
29

Este post é antigo e provavelmente está resolvido, mas eu tive o mesmo problema. Resolvi isso criando uma visão da tabela original especificando a nova ordem das colunas.

A partir daqui, eu poderia usar a visualização ou criar uma nova tabela a partir da visualização.

    CRIAR VISUALIZAR original_tab_vw AS
    SELECIONE a.col1, a.col3, a.col4, a.col2
    FROM original_tab a
    ONDE a.col1 NÃO É NULO - ou qualquer outra coisa
    SELECT * INTO new_table FROM original_tab_vw

Renomeie ou elimine a tabela original e defina o nome da nova tabela para a tabela antiga.

Ken
fonte
2
Esta parece ser uma solução bastante razoável. É uma pena que não existam ferramentas GUI para automatizar este procedimento.
Quolonel Perguntas
4
boa solução, mas apenas os tipos de dados são copiados (sem chave primária, etc.)
Regisz
1
Alternativamente - apenas use a visualização com as colunas reordenadas como estão. Deve haver degradação de desempenho mínima.
pscl
1
essa é a melhor solução.
Nikolay Shindarov
23

Uma, embora seja uma opção desajeitada para reorganizar as colunas quando a ordem das colunas deve ser absolutamente alterada e as chaves estrangeiras estão em uso, é primeiro despejar todo o banco de dados com dados e, em seguida, despejar apenas o esquema ( pg_dump -s databasename > databasename_schema.sql). Em seguida, edite o arquivo de esquema para reorganizar as colunas como desejar, recrie o banco de dados do esquema e, finalmente, restaure os dados no banco de dados recém-criado.

Ville
fonte
1
Por que um downvote? Como a resposta aceita indica, citando o PostgreSQL Wiki: »A única maneira de alterar a ordem das colunas é recriar a tabela ou adicionar colunas e girar os dados até chegar ao layout desejado.» Essa solução não é a ideal (nenhuma dessas respostas está na ausência de uma operação integrada para realizar a tarefa), mas fornece uma maneira de reorganizar as colunas em uma tabela.
Ville
1
Digo novamente, não há boas maneiras de fazer isso, e o que delineei acima é uma maneira válida de reorganizar as colunas, se for absolutamente necessário reorganizá-las. Se você votar contra minha resposta, comente por que você acha que é uma solução inaceitável.
Ville
3
Na verdade, esta é uma solução muito boa quando a tabela é uma chave estrangeira em outras tabelas. Todas as outras soluções não funcionam neste cenário. Por último, use pg_dump --column-inserts -s databasename> databasename_schema.sql
Alejandro Salamanca Mazuelo
9

Não acho que você possa no momento: veja este artigo na wiki do Postgresql .

As três soluções alternativas deste artigo são:

  1. Recrie a mesa
  2. Adicionar colunas e mover dados
  3. Esconda as diferenças com uma vista.
Mike Woodhouse
fonte
5

Abra a tabela no PGAdmin e no painel SQL na parte inferior copie a instrução SQL Create Table. Em seguida, abra a ferramenta de consulta e cole. Se a tabela tiver dados, altere o nome da tabela para 'novo_nome', caso contrário, exclua o comentário "-" na linha Eliminar Tabela. Edite a sequência da coluna conforme necessário. Cuidado com a vírgula ausente / supérflua na última coluna, caso você a tenha movido. Execute o novo comando SQL Create Table. Atualize e ... voilà.

Para tabelas vazias na fase de design, este método é bastante prático.

Caso a tabela contenha dados, precisamos reorganizar a sequência das colunas dos dados também. Isso é fácil: use INSERTpara importar a tabela antiga para sua nova versão com:

INSERT INTO new ( c2, c3, c1 ) SELECT * from old;

... onde c2, c3, c1são as colunas c1, c2, c3da antiga mesa em suas novas posições. Observe que, neste caso, você deve usar um nome 'novo' para a tabela 'antiga' editada ou perderá seus dados . No caso dos nomes das colunas serem muitos, longos e / ou complexos, use o mesmo método acima para copiar a nova estrutura da tabela em um editor de texto e crie a nova lista de colunas antes de copiá-la para a INSERTinstrução.

Depois de verificar se está tudo bem, DROPvá para a tabela antiga e mude o nome 'novo' para 'antigo' usando ALTER TABLE new RENAME TO old;e pronto.

marcopolo
fonte
1

Eu estava trabalhando para reordenar várias tabelas e não queria ter que escrever as mesmas consultas repetidamente, então fiz um script para fazer tudo para mim. Essencialmente, ele:

  1. Obtém o SQL de criação de tabela de pg_dump
  2. Obtém todas as colunas disponíveis do despejo
  3. Coloca as colunas na ordem desejada
  4. Modifica a pg_dumpconsulta original para criar uma tabela reordenada com dados
  5. Cai a mesa velha
  6. Renomeia a nova tabela para corresponder à tabela antiga

Ele pode ser usado executando o seguinte comando simples:

./reorder.py -n schema -d database table \
    first_col second_col ... penultimate_col ultimate_col --migrate

Ele imprime o sql para que você possa verificá-lo e testá-lo, esse foi um grande motivo pelo qual eu o baseei pg_dump. Você pode encontrar o repositório github aqui .

GammaGames
fonte
0

Eu uso Django e requer coluna id em cada tabela se você não quiser ter dor de cabeça. Infelizmente, fui descuidado e minha tabela bp.geo_location_vague não continha este campo. Eu iniciei um pequeno truque. Passo 1:

CREATE VIEW bp.geo_location_vague_vw AS
    SELECT 
        a.id, -- I change order of id column here. 
        a.in_date,
        etc
    FROM bp.geo_location_vague a

Etapa 2: (sem criar tabela - a tabela será criada automaticamente!)

SELECT * into bp.geo_location_vague_cp2 FROM bp.geo_location_vague_vw

Etapa 3:

CREATE SEQUENCE bp.tbl_tbl_id_seq;
ALTER TABLE bp.geo_location_vague_cp2 ALTER COLUMN id SET DEFAULT nextval('tbl_tbl_id_seq');
ALTER SEQUENCE bp.tbl_tbl_id_seq OWNED BY bp.geo_location_vague_cp2.id;
SELECT setval('tbl_tbl_id_seq', COALESCE(max(id), 0)) FROM bp.geo_location_vague_cp2;

Porque preciso ter um grande pseudótipo serial na tabela. Depois de SELECT * na pg, será criado o tipo bigint insetad bigserial.

passo 4: agora podemos eliminar a visão, eliminar a tabela de origem e renomear a nova tabela com o nome antigo. O truque foi encerrado com sucesso.

Orlov Const
fonte