web-dev-qa-db-fra.com

utiliser mysql SUM () dans une clause WHERE

suppose que j'ai cette table

id | cash 
1    200
2    301
3    101
4    700

et je veux retourner la première ligne dans laquelle la somme de tout l'argent précédent est supérieure à une certaine valeur:

Ainsi, par exemple, si je veux retourner la première ligne dans laquelle la somme de tout l'argent précédent est supérieur à 500, il faut retourner à la ligne 3

Comment puis-je faire cela en utilisant la déclaration mysql?

l'utilisation de WHERE SUM(cash) > 500 ne fonctionne pas

44
kamikaze_pilot

Vous pouvez uniquement utiliser des agrégats à des fins de comparaison dans la clause HAVING:

GROUP BY ...
  HAVING SUM(cash) > 500

La clause HAVING nécessite que vous définissiez une clause GROUP BY.

Pour obtenir la première ligne où la somme de toutes les espèces précédentes est supérieure à une certaine valeur, utilisez:

SELECT y.id, y.cash
  FROM (SELECT t.id,
               t.cash,
               (SELECT SUM(x.cash)
                  FROM TABLE x
                 WHERE x.id <= t.id) AS running_total
         FROM TABLE t
     ORDER BY t.id) y
 WHERE y.running_total > 500
ORDER BY y.id
   LIMIT 1

Étant donné que la fonction d'agrégation se produit dans une sous-requête, l'alias de colonne correspondant peut être référencé dans la clause WHERE.

89
OMG Ponies

Pas testé, mais je pense que ce sera proche?

SELECT m1.id
FROM mytable m1
INNER JOIN mytable m2 ON m1.id < m2.id
GROUP BY m1.id
HAVING SUM(m1.cash) > 500
ORDER BY m1.id
LIMIT 1,2

L'idée est de résumer toutes les lignes précédentes, d'obtenir uniquement celles où la somme des lignes précédentes est> 500, puis de sauter une et de retourner la suivante.

5
Eric Petroelje

En général, une condition de la clause WHERE d'une requête SQL ne peut référencer qu'une seule ligne. Le contexte d'une clause WHERE est évalué avant qu'un ordre soit défini par un ORDER BY, et il n'y a pas d'ordre implicite dans une table SGBDR.

Vous pouvez utiliser une table dérivée pour joindre chaque ligne au groupe de lignes avec une valeur id moindre et produire la somme de chaque groupe de somme. Testez ensuite où la somme correspond à votre critère.

CREATE TABLE MyTable ( id INT PRIMARY KEY, cash INT );

INSERT INTO MyTable (id, cash) VALUES
  (1, 200), (2, 301), (3, 101), (4, 700);

SELECT s.*
FROM (
  SELECT t.id, SUM(prev.cash) AS cash_sum
  FROM MyTable t JOIN MyTable prev ON (t.id > prev.id)
  GROUP BY t.id) AS s
WHERE s.cash_sum >= 500
ORDER BY s.id
LIMIT 1;

Sortie:

+----+----------+
| id | cash_sum |
+----+----------+
|  3 |      501 |
+----+----------+
4
Bill Karwin

Lorsque vous utilisez des fonctions d'agrégation pour filtrer, vous devez utiliser une instruction HAVING.

SELECT *
FROM tblMoney
HAVING Sum(CASH) > 500
0
Robot