Eu estou querendo saber se o PostgreSQL tem uma consulta de atualização um pouco como sua sintaxe de valores de inserção.
Eu tenho um conjunto atualizado de dados neste formulário atualmente:
INSERT INTO bought_in_control_panel(ID,PARENT_ID,BOUGHT_IN_FORM_TYPE_ID,PRIORITY,NAME,HEADING,DESCRIPTION,ICON,BOUGHT_IN_CONTROL_PANEL_FILE_ID)
VALUES(109,1,28,100,'Tooling','Tooling','Enter your Machine Tools here','tooling.png',null);
e quero atualizar as linhas que já estão lá para os novos dados, estou procurando algo como o seguinte, onde posso atualizar todas as linhas sem me repetir:
UPDATE ON ID
bought_in_control_panel(ID,PARENT_ID,BOUGHT_IN_FORM_TYPE_ID,PRIORITY,NAME,HEADING,DESCRIPTION,ICON,BOUGHT_IN_CONTROL_PANEL_FILE_ID)
VALUES(
(109,1,28,100,'Tooling','Tooling','Enter your Machine Tools here','tooling.png',null),
(1,0,1,200,'Bought In','Bought In','','boughtin.png',null)
);
O acima verificaria os ID
valores correspondentes e atualizaria as correspondências com os novos dados.
Observação: estou realmente procurando evitar o mapeamento manual de todos os nomes das colunas. O PostgreSQL já conhece minhas colunas e já as mapeei nos dados. Por que fazer isso novamente em um formato mais longo?
Se você deseja apenas atualizar os dados, não sei para que
INSERT
serve a declaração na sua pergunta.Se você deseja apenas atualizar várias linhas com uma única instrução, pode estar procurando por isso:
Na verdade, existe uma variante de sintaxe mais curta para isso, disponível desde o Postgres 8.2 (lançado em 2006!). As notas de lançamento:
Aplicado à sua consulta:
Você ainda tem que listar todas as colunas, mas você pode cortar alguns ruídos e é mais fácil montar uma lista, copiá-la e prefixar o alias da tabela de origem. Você também pode fazer isso dinamicamente. Veja abaixo.
Também usando uma subconsulta, que funciona tão bem quanto um CTE aqui, mas com um pouco menos de sobrecarga (desempenho).
Você pode até misturar listas e colunas únicas livremente , se quiser. Nenhuma diferença no resultado, mas pode ser útil para formatação ou, mais importante, para comandos gerados dinamicamente:
Está tudo no manual se você olhar de perto.
Falando em SQL dinâmico , esta resposta relacionada no SO demonstra como buscar a lista de colunas do catálogo do sistema
pg_attribute
e executar tudo em uma função:IIRC postgres não tem
MERGE
ou similar (embora pareça estar sendo falado para versões posteriores: http://wiki.postgresql.org/wiki/SQL_MERGE ).Se você sabe que todas as linhas em questão existem, você pode fazer algo como:
adicionando um extra
UNION
para cada linha subsequente que precisa de atualização, embora sejamos bastante prolixos para apenas algumas atualizações e possam não ser muito eficientes (esse conjunto deUNION
s produzindo "newdata" será lançado em uma tabela temporária, potencialmente no disco , e não haverá índice no ID nessa tabela temporária, o que pode ser significativo se houver muitas linhas).OBSERVAÇÃO: A conversão para
BOUGHT_IN_CONTROL_PANEL_FILE_ID
é garantir que o planejador de consulta conheça o tipo (já vi isso causar problemas no MSSQL com ele decidindo antecipadamente que aNULL
deveria ser eINT
, em seguida, encontrando um tipo de caractere nessa posição em umaUNION
cláusula posterior - portanto, sempre especifico um tipo de coluna paraNULL
valores literais ao usarUNION
)Para tornar a primeira linha no mesmo formato das subsequentes, para tornar a geração programática desse tipo de instrução um pouco mais fácil, este hack fará o truque no MSSQL:
Advertência 1: esta deve ser uma sintaxe válida para MSSQL, mas eu não a testei e não sei quão padrão é toda a sintaxe, então você pode precisar de ajustes para postgres (por exemplo, nem todos os intérpretes de consulta permitem que você não nomeando as colunas após o primeiro SELECT em uma sequência de UNIONs).
Advertência 2: isso parece um pouco hacky e é consideravelmente mais detalhado do que o ideal no seu exemplo.
Como alternativa, solte os novos dados em uma tabela temporária e execute duas instruções para atualizar as linhas que existem nos dados atuais (então insira aquelas que não existem, se você estiver tentando em
UPSERT
vez de apenasUPDATE
), envolvendo isso em um explícito transação para garantir que você obtenha consistência de tudo ou nada para a operação - isso provavelmente seria muito mais limpo, apesar de não ser uma única instrução.