Fonction d'agrégation dans une requête de mise à jour SQL?

98

J'essaye de définir la valeur dans une table à la somme des valeurs dans une autre table. Quelque chose dans ce sens:

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

Bien sûr, dans l'état actuel des choses, cela ne fonctionnera pas - SETne prend pas en charge SUMet ne prend pas en charge GROUP BY.

Je devrais le savoir, mais mon esprit dessine un vide. Qu'est-ce que je fais mal?

Margaret
la source
Excellente question ... j'aimerais pouvoir voter plus d'une fois.
Joe

Réponses:

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
la source
40
J'ai mis les trois requêtes côte à côte et j'ai exécuté un plan d'exécution. Cette réponse avait un coût de 5%.
Margaret
Élégant, facile à mettre en œuvre ... Où étiez-vous toute la journée ??? Je me cogne la tête dessus depuis plus d'une heure maintenant :)
Ange1
1
Important: faites attention si l'un des champs par lesquels vous regroupez peut être nul (par exemple, champ3 ci-dessus). vous devrez modifier la `` jointure '' pour en tenir compte,
sinon
10

Utilisation:

UPDATE table1
   SET field1 = (SELECT SUM(t2.field2) 
                   FROM TABLE2 t2 
                  WHERE t2.field3 = field2)
Poneys OMG
la source
14
J'ai mis les trois requêtes côte à côte et j'ai exécuté un plan d'exécution. Cette réponse avait un coût de 44%.
Margaret
cela n'a pas fonctionné pour moi, car t2.filed3 était le même nom que table1.field2, donc la jointure effectuée en coulisses ne fonctionnait pas correctement. (Je suppose qu'il y a une jointure dans les coulisses)
Joe
5

Ou vous pouvez utiliser un mélange de réponses JBrooks et OMG Ponies :

UPDATE table1
   SET field1 = (SELECT SUM(field2)
                   FROM table2 AS t2
                  WHERE t2.field3 = t1.field3)
  FROM table1 AS t1
Paulo Santos
la source
16
J'ai mis les trois requêtes côte à côte et j'ai exécuté un plan d'exécution. Cette réponse avait un coût de 51%.
Margaret
Oki Doki! Et merci pour les commentaires. Je vais l'ajouter à ma boîte à outils. :-)
Paulo Santos
Ce serait parce que vous utilisez un SUBQUERY qui doit déclencher la SUM () chaque ligne valide, même avec l'optimiseur
clifton_h
4

Une bonne situation pour utiliser 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
la source
3

Je sais que la question est étiquetée SQL Server mais soyez prudent avec UPDATE avec JOIN si vous utilisez PostgreSQL . La réponse @JBrooks ne fonctionnera pas:

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

Vous devrez l'adapter à:

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

Voir le paramètre from_listdans la documentation pour savoir pourquoi FROMPostgreSQL est considéré comme une auto-jointure: https://www.postgresql.org/docs/9.5/static/sql-update.html#AEN89239

Bludwarf
la source
0

Vous pouvez également utiliser CTE comme ci-dessous.

;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
la source