Как суммировать столбцы по нескольким условиям в GROUP BY - PullRequest
14 голосов
/ 02 мая 2010

Я пытаюсь вернуть список учетных записей с их балансами, исходами и доходами

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

Вот что у меня сейчас есть. Может кто-нибудь объяснить, где я иду не так?

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]

UPDATE

Исправлен синтаксис левого соединения t2 согласно комментарию ниже.

Результат, который я ожидаю, очевидно, очевиден из вопроса. Для 6 учетных записей SQL должен вернуть 6 учетных записей с их балансом, доходом и результатом этой учетной записи.

Проблема с предоставленным мною SQL состояла в том, что числа неверны! Что касается комментариев, я думаю, что проблема связана с объединением нескольких раз, что неправильно суммирует суммы.

Ответы [ 4 ]

18 голосов
/ 02 мая 2010

Поскольку вы не сказали нам , что происходит не так (то есть опишите поведение, которое вы получаете в дополнение к описанию поведения, которое вы ожидаете), трудно сказать, где, но есть пара возможностей. Нил указывает на один. Другое состоит в том, что, поскольку вы присоединяетесь к таблице транзакций три раза, вы объединяете транзакции с транзакциями и получаете повторы. Вместо этого присоединитесь к таблице транзакций один раз и измените способ суммирования столбца 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]

Вы можете использовать CASE выражений в качестве более удобочитаемой альтернативы умножениям:

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]
6 голосов
/ 02 мая 2010

Вы имели в виду:

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] 
3 голосов
/ 02 мая 2010

Я не уверен, зачем вам нужны множественные объединения. Не могли бы вы просто сделать что-то вроде:

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]
1 голос
/ 02 мая 2010

Соединение для транзакции t2 должно быть на t2 , как в on t2.ACCOUNT_ID = a.ACCOUNT_ID

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...