web-dev-qa-db-fra.com

Comment faire la somme des colonnes sur plusieurs conditions dans un GROUP BY

J'essaie de renvoyer une liste de comptes avec leurs soldes, résultats et revenus

Account            Transaction
-------            -----------
AccountID          TransactionID
BankName           AccountID
Locale             Amount
Status

Voici ce que j'ai actuellement. Quelqu'un pourrait-il expliquer où je me trompe?

select
    a.ACCOUNT_ID,
    a.BANK_NAME,
    a.LOCALE,
    a.STATUS,
    sum(t1.AMOUNT) as BALANCE,
    sum(t2.AMOUNT) as OUTCOME,
    sum(t3.AMOUNT) as INCOME
from ACCOUNT a
left join TRANSACTION t1 on t1.ACCOUNT_ID = a.ACCOUNT_ID
left join TRANSACTION t2 on t2.ACCOUNT_ID = a.ACCOUNT_ID and t2.AMOUNT < 0
left join TRANSACTION t3 on t3.ACCOUNT_ID = a.ACCOUNT_ID and t3.AMOUNT > 0
group by a.ACCOUNT_ID, a.BANK_NAME, a.LOCALE, a.[STATUS]

MISE À JOUR

Ont corrigé la syntaxe de jointure gauche t2 comme indiqué dans le commentaire ci-dessous.

Le résultat que j'attends est, espérons-le, évident d'après la question. Pour 6 comptes, le SQL doit renvoyer 6 comptes avec leur solde, revenu et résultat de ce compte.

Le problème avec le SQL que j'ai fourni était que les nombres sont faux! Selon les commentaires, je pense que le problème vient du fait de se joindre à plusieurs reprises, ce qui fait une somme incorrecte des montants.

16
David

Puisque vous ne nous avez pas dit ce qui ne va pas (c'est-à-dire, décrivez le comportement que vous obtenez en plus de décrire le comportement que vous attendez), il est difficile de dire où, mais il y a quelques possibilités . Neil en souligne un. Un autre est que, puisque vous vous inscrivez trois fois sur la table des transactions, vous associez des transactions avec des transactions et obtenez des répétitions. À la place, rejoignez une seule fois la table des transactions et modifiez la façon dont vous additionnez la colonne Amount.

Select
    a.ACCOUNT_ID,
    a.BANK_NAME,
    a.LOCALE,
    a.STATUS,
    sum(t.AMOUNT) as BALANCE,
    sum((t.AMOUNT < 0) * t.AMOUNT) As OUTGOING,
    sum((t.AMOUNT > 0) * t.AMOUNT) As INCOMING
From ACCOUNT a
Left Join TRANSACTION t On t.ACCOUNT_ID = a.ACCOUNT_ID
Group By a.ACCOUNT_ID, a.BANK_NAME, a.LOCALE, a.[STATUS]

Vous pouvez utiliser les expressions CASE comme alternative plus lisible aux multiplications:

Select
    a.ACCOUNT_ID,
    a.BANK_NAME,
    a.LOCALE,
    a.[STATUS],
    sum(t.AMOUNT) As BALANCE,
    sum(CASE WHEN t.AMOUNT < 0 THEN t.AMOUNT ELSE 0 end) As OUTCOME,
    sum(CASE WHEN t.AMOUNT > 0 THEN t.AMOUNT ELSE 0 end) As INCOME
From ACCOUNT a
Left Join [TRANSACTION] t On t.ACCOUNT_ID = a.ACCOUNT_ID
Group By a.ACCOUNT_ID, a.BANK_NAME, a.LOCALE, a.[STATUS]
22
outis

Vouliez-vous dire:

select 
    a.ACCOUNT_ID, 
    a.BANK_NAME, 
    a.LOCALE, 
    a.STATUS, 
    sum(t1.AMOUNT) as BALANCE, 
    sum(CASE WHEN t2.AMOUNT < 0 THEN t2.Amount ELSE 0 END) as OUTCOME, 
    sum(CASE WHEN t3.AMOUNT > 0 THEN t3.Amount ELSE 0 END) as INCOME 
from 
    ACCOUNT a 
    left join TRANSACTION t1 on t1.ACCOUNT_ID = a.ACCOUNT_ID 
    left join TRANSACTION t2 on t2.ACCOUNT_ID = a.ACCOUNT_ID
    left join TRANSACTION t3 on t3.ACCOUNT_ID = a.ACCOUNT_ID
group by 
    a.ACCOUNT_ID, a.BANK_NAME, a.LOCALE, a.[STATUS] 
6
Mitch Wheat

Je ne sais pas pourquoi vous auriez besoin des jointures multiples. Ne pourriez-vous pas simplement faire quelque chose comme:

Select
    a.ACCOUNT_ID
    , a.BANK_NAME
    , a.LOCALE
    , a.STATUS
    , Sum ( t.Amount ) As Balance
    , Sum( Case When t.Amount < 0 Then Amount End ) As Outcome
    , Sum( Case When t.Amount > 0 Then Amount End ) As Income
From ACCOUNT a
    Left Join TRANSACTION t 
        On t.ACCOUNT_ID = a.ACCOUNT_ID
Group By a.ACCOUNT_ID, a.BANK_NAME, a.LOCALE, a.[STATUS]
3
Thomas

La jointure pour TRANSACTION t2 doit être sur t2 comme dans on t2.ACCOUNT_ID = a.ACCOUNT_ID

1
Neil Moss