Função agregada em uma consulta de atualização SQL?

98

Estou tentando definir o valor em uma tabela para a soma dos valores em outra tabela. Algo nesse sentido:

UPDATE table1
SET field1 = SUM(table2.field2)
FROM table1
INNER JOIN table2 ON table1.field3 = table2.field3
GROUP BY table1.field3

Claro, do jeito que está, não vai funcionar - SETnão dá suporte SUMe não dá suporte GROUP BY.

Eu deveria saber disso, mas minha mente está em branco. O que estou fazendo de errado?

Margaret
fonte
Ótima pergunta ... gostaria de poder votar a favor mais de uma vez.
Joe

Respostas:

148
UPDATE t1
SET t1.field1 = t2.field2Sum
FROM table1 t1
INNER JOIN (select field3, sum(field2) as field2Sum
   from table2
  group by field3) as t2
on t2.field3 = t1.field3  
JBrooks
fonte
40
Coloquei as três consultas lado a lado e executei um plano de execução. Essa resposta teve um custo de 5%.
Margaret
Elegante, fácil de implementar ... Onde você esteve o dia todo ??? Eu tenho batido minha cabeça por mais de uma hora agora :)
Ange1
1
Importante: observe se algum dos campos pelos quais você está agrupando pode ser anulável (por exemplo, campo 3 acima). você precisa modificar o 'join' para contabilizar isso ou suas somas serão imprecisas ( stackoverflow.com/a/14366034/16940 )
Simon_Weaver
10

Usar:

UPDATE table1
   SET field1 = (SELECT SUM(t2.field2) 
                   FROM TABLE2 t2 
                  WHERE t2.field3 = field2)
Pôneis OMG
fonte
14
Coloquei as três consultas lado a lado e executei um plano de execução. Essa resposta teve um custo de 44%.
Margaret
isso não funcionou para mim, porque t2.filed3 era o mesmo nome que table1.field2, então a junção executada nos bastidores não funcionou corretamente. (Eu assumo que há uma junção nos bastidores)
Joe
5

Ou você pode usar uma mistura de respostas JBrooks e OMG Ponies :

UPDATE table1
   SET field1 = (SELECT SUM(field2)
                   FROM table2 AS t2
                  WHERE t2.field3 = t1.field3)
  FROM table1 AS t1
Paulo santos
fonte
16
Coloquei as três consultas lado a lado e executei um plano de execução. Essa resposta teve um custo de 51%.
Margaret
Okie dokie! E obrigado pelo feedback. Vou adicioná-lo à minha caixa de ferramentas. :-)
Paulo Santos
Isso seria porque você está usando um SUBQUERY que deve disparar SUM () em todas as linhas válidas, mesmo com o otimizador
clifton_h
4

Uma boa situação para usar CROSS APPLY

UPDATE t1
   SET t1.field1 = t2.field2Sum
  FROM table1 t1
 CROSS APPLY (SELECT SUM(field2) as field2Sum
                FROM table2 t2
               WHERE t2.field3 = t1.field3) AS t2
Jonathan Roberts
fonte
3

Eu sei que a pergunta está marcada como SQL Server, mas tome cuidado com UPDATE com JOIN se você estiver usando PostgreSQL . A resposta do @JBrooks não funcionará:

UPDATE t1
SET t1.field1 = t2.field2Sum
FROM table1 t1
INNER JOIN (...) as t2
on t2.field3 = t1.field3  

Você terá que adaptá-lo para:

UPDATE table1 t1
SET t1.field1 = t2.field2Sum
FROM (...) as t2
WHERE t2.field3 = t1.field3  

Veja o parâmetro from_list no documento para saber por que FROMé considerado pelo PostgreSQL como uma autojunção: https://www.postgresql.org/docs/9.5/static/sql-update.html#AEN89239

Bludwarf
fonte
0

Você também pode usar o CTE como abaixo.

;WITH t2 AS (
    SELECT field3, SUM(field2) AS field2
    FROM table2
    GROUP BY field3
)
UPDATE table1
SET table1.field1 = t2.field2
FROM table1
INNER JOIN t2 ON table1.field3 = t2.field3
Karan
fonte