简体   繁体   中英

Grouping columns in SQL Server

I am trying to group the credit and debit account numbers for money transaction.

http://sqlfiddle.com/#!18/67ecd/4/0

I am able to group if there are multiple transactions on the same credit and debit account.

CREATE Table TestTable 
(
    DebitAccountNumber NVARCHAR(10),
    CredtiAccountNumber NVARCHAR(10),
    Amount MONEY
)

INSERT INTO TestTable 
VALUES ('A', 'C', 10), ('C', 'A', 20), ('A', 'C', 40);

SELECT  
    DebitAccountNumber, 
    CredtiAccountNumber, 
    SUM(amount) 
FROM 
    TestTable
GROUP BY
    DebitAccountNumber, CredtiAccountNumber

Since credit and debit account is happening on the same account, the expected output is A -> C 30.

Could anyone please help me with the query?

I suspect you want:

select accountnumber, sum(amount)
from ((select DebitAccountNumber as accountnumber, - amount as amount
       from testtable
      ) union all
      (select CreditAccountNumber as accountnumber, amount
       from testtable
      )
     ) cd
group by accountnumber;

In SQL Server, you can use apply :

select v.accountnumber, sum(v.amount)
from testtable tt cross apply
     (values (debitaccountnumber, - amount), (creditaccountnumber, amount)
     ) v(accountnumber, amount)
group by v.accountnumber;
WITH cte AS
 ( 
   SELECT
      -- "normalize" debitor and creditor to: account#1 < account#2
      CASE WHEN DebitAccountNumber < CreditAccountNumber THEN DebitAccountNumber  ELSE CreditAccountNumber END AS Account1,
      CASE WHEN DebitAccountNumber < CreditAccountNumber THEN CreditAccountNumber ELSE DebitAccountNumber  END AS Account2,
      -- adjust sign when accounts switched   
      CASE WHEN DebitAccountNumber < CreditAccountNumber THEN Amount              ELSE -Amount             END AS amount
   FROM TestTable
 )
SELECT
   Account1,
   Account2,
   Sum(amount) -- might be negative 
FROM cte
GROUP BY
   Account1,
   Account2
;

See fiddle

Edit:

If you want to avoid negative amounts you can "normalize" it again:

WITH normalized AS
 ( 
   SELECT
      -- "normalize" debitor and creditor to: account#1 < account#2
      CASE WHEN DebitAccountNumber < CreditAccountNumber THEN DebitAccountNumber  ELSE CreditAccountNumber END AS Account1,
      CASE WHEN DebitAccountNumber < CreditAccountNumber THEN CreditAccountNumber ELSE DebitAccountNumber  END AS Account2,
      -- adjust sign when accounts switched   
      CASE WHEN DebitAccountNumber < CreditAccountNumber THEN Amount              ELSE -Amount             END AS amount
   FROM TestTable
 ),
summed as
 (
   SELECT
      Account1,
      Account2,
      Sum(amount) as Amount -- might be negative 
   FROM normalized
   GROUP BY
      Account1,
      Account2
 )
select
   case when Amount > 0 then Account1 else Account2 end as Debitor,
   case when Amount > 0 then Account2 else Account1 end as Creditor,
   abs(Amount) as Amount
from summed
;

See fiddle

Based on @GordonLinoff 's approach, having in mind the result, you accepted from @dnoeth , my suggested answer would be:

SELECT v.CreditAccountNumber, v.DebitAccountNumber, SUM(v.Amount) AS SumAmount
FROM TestTable AS tt
CROSS APPLY
     (VALUES
        (DebitAccountNumber, CreditAccountNumber, Amount),
        (CreditAccountNumber, DebitAccountNumber, -Amount)
     ) AS v(DebitAccountNumber, CreditAccountNumber, Amount)
GROUP BY v.CreditAccountNumber, v.DebitAccountNumber
HAVING SUM(v.Amount) > 0
ORDER BY 1, 2;

Here's a fiddle for it .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM