4
votes

utiliser SUM avec la jointure gauche me donne un mauvais résultat

J'ai donc:

min(A.id)   SUM(A.amount)   COUNT(B.id)
1           50              3
3           10              0

Je lance cette requête:

min(A.id)   SUM(A.amount)   COUNT(B.id)
1           75              3
3           10              0

J'obtiens:

SELECT min(A.id), SUM(A.amount), COUNT(B.id) FROM A
LEFT JOIN B ON A.id = B.A_id
GROUP BY A.type


10 commentaires

Veuillez marquer uniquement le SGBD que vous utilisez.


Lorsque vous faites votre jointure, vous avez deux lignes dans tableb qui ont un type de 1. Vous obtenez donc toutes les lignes dans tablea avec le type a pour CHAQUE ligne dans tableb. Retirez l'agrégation et vous verrez les lignes renvoyées.


Exécutez la requête sans aucune agrégation ... db-fiddle.com/f/sAqaUyG1E9rHyqsXkoF2pz/0 Voir. Maintenant, il est évident pourquoi vous obtenez ce résultat


SUM ne fait pas la somme des lignes distinctes, il additionne toutes les lignes de ce groupe. Essayez SELECT * FROM A LEFT JOIN B ON A.id = B.A_id WHERE a.type = 0; et vous verrez que vous obtenez 3 lignes avec la valeur 25 pour montant , et 3 * 25 = 75 pas 50 .


merci @larnu je suis conscient de la manière d'y parvenir


SQL Server et MySQL sont des produits complètement différents. Lequel est-ce ???


son propos de sql-server (mysql a été supprimé mis à jour), quel est le moyen d'obtenir 50 et 3 ou ce n'est pas possible?


Le résultat obtenu est correct, vous avez 2 fois A_ID = 1 et un pour A_ID = 2 .. 2x25 +25


Dans SQL Server, cela est simple à contourner. Dans MySQL 5.7, vous n'avez pas de chance, j'en ai peur. Je veux dire que tu "pourrais" probablement le faire, mais ça va être douloureux au mieux.


@all oui le résultat est correct ma question est: comment puis-je obtenir mon résultat attendu s'il vous plaît?


3 Réponses :


0
votes

une façon de faire cela serait d'utiliser ROW_NUMBER():

WITH CTE AS (SELECT A.id AS Aid,
            A.[type],
            A.amount,
            B.id AS bid,
            txt,
            ROW_NUMBER() OVER (PARTITION BY A.id ORDER BY B.id) AS RN
     FROM A
          LEFT JOIN B ON A.id = B.A_ID)
SELECT MIN(Aid) AS Min_A_ID,
       SUM(CASE RN WHEN 1 THEN amount END) AS Amount,
       COUNT(bid) AS BCount
FROM CTE
GROUP BY [type];

Je recommande également de se débarrasser de ce type de données text et en utilisant varchar(MAX).


0 commentaires

1
votes

Cela peut se produire lorsque vous faites une somme à partir d'une relation 1-N.

Les enregistrements correspondants peuvent multiplier le résultat.

Par exemple, quand 1 enregistrements dans A sont joints avec 2 dans B, il retourne 2 fois la quantité de A avant le GROUP BY. Donc, un SUM double alors A.amount.

Un moyen de contourner qui consiste à utiliser des sous-requêtes qui rejoignent un à un.

Et un COUNT DISTINCT peut être utilisé pour compter les identifiants uniques.
C'est donc juste un moyen d'obtenir la SOMME de A correcte.

SELECT 
 q1.type, 
 q1.min_id, 
 q2.amount, 
 COALESCE(q1.totalB, 0) as totalB
FROM 
(
   SELECT 
    A.type,
    MIN(A.id) AS min_id, 
    COUNT(DISTINCT B.id) AS totalB
    FROM A
    LEFT JOIN B ON B.A_id = A.id
    GROUP BY A.type
 ) AS q1
JOIN
(
  SELECT 
   type,
   SUM(amount) AS amount 
  FROM A 
  GROUP BY type
) AS q2 ON q2.type = q1.type

Vue sur DB Fiddle

Le SQL est testé pour MySql. Mais c'est un SQL standard ANSI qui fonctionnerait sur presque tous les SGBDR, y compris MS Sql Server.


0 commentaires

2
votes

Juste une version plus courte de la solution. Il compte les B_ID en premier dans la requête interne, je dois donc faire la somme des comptes dans la requête externe.

SELECT  min(A.id), SUM(A.amount), Sum(Bid) FROM A
LEFT JOIN (select count(id) as Bid, A_id from B group by A_id) as Bcount  
ON A.id = Bcount.A_id
GROUP BY A.type


0 commentaires