Get the credit and the debit from the transaction details using sql - sql

I have table structure like
From|To |Amt |In_out
A | B | 100 |0
B | A | 200 |1
C | D | 250 |0
where the last column defines the direction of cash flow
I want to get the output as
From | To | Amount Transacted | Debited | Credited
A | B | 300 |100 | 200
C | D | 250 |250 | 0
I tried various queries like
select DISTINCT r.to,r.to,r.Amt,r.In_out
,sum(r.Amt) as credited
from
Records as r
join
Records as s
on
(r.from <> s.from and r.to == s.from)
where
r.from <>s.from
--GROUP by r.from
can Anyone help me with this?

In many databases, you can use least() and greatest():
select least(from, to), greatest(from, to),
sum(amount),
sum(case when in_out = 0 and from = least(from, to) or
in_out = 1 and to = least(from, to)
then amount else 0
end) as debited,
sum(case when in_out = 0 and to = least(from, to) or
in_out = 1 and from = least(from, to)
then amount else 0
end) as credited
from records
group by least(from, to), greatest(from, to);
If your database doesn't support these functions, you can use case expressions to accomplish the same thing.

You want greatest() / least():
select least(from, to) from, greatest(from, to) to,
sum(amt) AmountTransacted,
sum(case when In_out = 0 then Amt else 0 end) Debited,
sum(case when In_out = 1 then Amt else 0 end) Credited
from table t
group by least(from, to), greatest(from, to);

Not sure of your RDBMS: Oracle or SQLite.
Anyway here's a way to achieve this in standard SQL
The trick is to inverse the From and To columns if the In_out is 1, in a UNION query, in order to GROUP the pairs of account correctly
SELECT u.From, u.To, SUM(Amt) AS "Amount Transacted",
SUM(CASE WHEN In_out=0 THEN Amt ELSE 0 END) AS Debited,
SUM(CASE WHEN In_out=1 THEN Amt ELSE 0 END) AS Credited
FROM
(
SELECT In_out, From, To, Amt FROM Records WHERE In_Out = 0
UNION ALL
SELECT In_out, To, From, Amt FROM Records WHERE In_Out = 1
) u
GROUP BY u.From, u.To

Related

How to get the grand total and the subtotal in one row?

Here is the expected output.
ID | GRAND_TOTAL | CHANNEL_1 | CHANNEL_2
1 | 100.00 | 50.00 | 50.00
2 | 500.00 | 100.00 | 400.00
But my query resulted like this:
ID | GRAND_TOTAL | CHANNEL_1 | CHANNEL_2
1 | 100.00 | 50.00 | 0
2 | 100.00 | 0 | 50.00
1 | 500.00 | 100.00 | 0
2 | 500.00 | 0 | 400.00
This is what I tried in my query.
SELECT
ID,
SUM(Amount) AS GRAND_TOTAL,
CASE WHEN CHANNEL_ID = 1 THEN AMOUNT ELSE 0 END CHANNEL_1,
CASE WHEN CHANNEL_ID = 2 THEN AMOUNT ELSE 0 END CHANNEL_2
FROM
CHANNEL_AMOUNT
GROUP BY
ID, CHANNEL_ID, AMOUNT
GROUP BY ____ means "I want one result row per ____". You don't want one result row per ID, cannel and amount, but only one per ID. Hence: GROUP BY id. Then you want sums per channel, so use SUM.
SELECT
id,
SUM(amount) AS grand_total,
SUM(CASE WHEN channel_id = 1 THEN amount ELSE 0 END) AS channel_1,
SUM(CASE WHEN channel_id = 2 THEN amount ELSE 0 END) AS channel_2
FROM channel_amount
GROUP BY id
ORDER BY id;
(In standard SQL this would be SUM(amount) FILTER (WHERE channel_id = 1), but SQL Server doesn't feature the filter clause yet, so we use a case expression inside the aggregation function.)
Looks like you want grouping by Id only
SELECT
ID,
SUM(Amount) AS GRAND_TOTAL,
SUM(CASE WHEN CHANNEL_ID = 1 THEN AMOUNT ELSE 0 END) CHANNEL_1,
SUM(CASE WHEN CHANNEL_ID = 2 THEN AMOUNT ELSE 0 END) CHANNEL_2
FROM
CHANNEL_AMOUNT
GROUP BY
ID
You can just try GROUP BY ID.
SELECT
ID,
SUM(Amount) AS GRAND_TOTAL,
CASE WHEN CHANNEL_ID = 1 THEN AMOUNT ELSE 0 END CHANNEL_1,
CASE WHEN CHANNEL_ID = 2 THEN AMOUNT ELSE 0 END CHANNEL_2
FROM
CHANNEL_AMOUNT
GROUP BY
ID

SQL calculate the sum of a column based on the date in two differents variables

I've a simple table in this forme :
BillItem (id,amount, volume, bill_date,....other fields)
I want to obtain in my query 4 differents sum of fields amount and volume based on the date
for example, in my table i've this data :
Id | amount | volume | bill_date | libelle
1 | 10 | 50 | 02/04/2016| bill1
2 | 20 | 55 | 02/04/2016| bill1
2 | 88 | 66 | 02/05/2016| bill1
3 | 30 | 60 | 03/05/2016| bill2
4 | 40 | 10 | 02/04/2016| bill3
5 | 50 | 20 | 02/05/2016| bill3
and the result must be like this :
bill1, sum_date_1=30, sum_date_2=88, sum_volume_date_1=105, sum_volume_date_2=66
bill2, sum_date_1=0, sum_date_2=30, sum_volume_date_1=0, sum_volume_date_2=60
bill3, sum_date_1=40, sum_date_2=50, sum_volume_date_1=10, sum_volume_date_2=20
i've this query with only two sum variable :
select ans.SERVICE_TYPE, ans.SERVICE_SUB_TYPE,
sum(bi.ACTUAL_AMOUNTVAT),sum(bi.ACTUAL_VOLUME), bi.BILL_DATE
from bill_item bi left outer join ANALYTIC_SECTION ans on ans.TREE_PATH=bi.REPORT_SECTION
where bi.account_id=7
and bi.BILL_DATE<='31/05/2016' and bi.BILL_DATE>='01/04/2016'
and ans.REPORT_TYPE='ARPE_REPORT' and ans.ACCOUNT_ID=7
group by ans.SERVICE_TYPE, ans.SERVICE_SUB_TYPE, bi.BILL_DATE;
Is it possible to obtain two differents sum for each field (amount and volume) ?
I've resolved the query like this :
select distinct ans.SERVICE_TYPE, ans.SERVICE_SUB_TYPE,
sum(Case when bi.BILL_DATE<'01/05/2016' then bi.ACTUAL_AMOUNTVAT ELSE 0 END) as amount_m1,
sum(Case when bi.BILL_DATE>='01/05/2016' then bi.ACTUAL_AMOUNTVAT ELSE 0 END) as amount_m,
sum(Case when bi.BILL_DATE<'01/05/2016' then bi.ACTUAL_VOLUME ELSE 0 END) as volume_m1,
sum(Case when bi.BILL_DATE>='01/05/2016' then bi.ACTUAL_VOLUME ELSE 0 END) as volume_m
--,bi.BILL_DATE
from bill_item bi left outer join ANALYTIC_SECTION ans on ans.TREE_PATH=bi.REPORT_SECTION
where bi.account_id=7
and bi.BILL_DATE<='06/05/2016' and bi.BILL_DATE>='06/04/2016'
and ans.REPORT_TYPE='ARPE_REPORT' and ans.ACCOUNT_ID=7
group by ans.SERVICE_TYPE, ans.SERVICE_SUB_TYPE;
Thank's All for your help
it looks to me like you want to summarize by each date and then return the value for the months in ascending fields?
It might work with a subquery and a ranking option, although this may not be the most efficient route.
Select t.Id
, Max(Case When t.BillRank=1 Then t.SumVolume Else Null End) As Volume1
, Max(Case When t.BillRank=2 Then t.SumVolume Else Null End) As Volume2
, Max(Case When t.BillRank=1 Then t.SumVAT Else Null End) As Vat1
, Max(Case When t.BillRank=2 Then t.SumVAT Else Null End) As Vat2
From ( Select ans.SERVICE_TYPE
, ans.SERVICE_SUB_TYPE
, Sum(bi.ACTUAL_AMOUNTVAT) As SumVAT
, Sum(bi.ACTUAL_VOLUME) As SumVolume
, bi.BILL_DATE
, bi.Id
, Rank() Over ( Partition By bi.Id Order By bi.BILL_DATE Asc ) As BillRank
From bill_item As bi
Left Outer Join ANALYTIC_SECTION as ans
On ans.TREE_PATH = bi.REPORT_SECTION
Group By ans.SERVICE_TYPE
, ans.SERVICE_SUB_TYPE
, bi.BILL_DATE
, bi.Id
) t
Group By t.Id;

How to SQL SUM with condition

I have a transaction table and want to calculate based on the type of transaction. How to?
Table:
id | amount | type
--------------------
01 | 230 | IncomingTransfer
02 | 100 | OutcomingTransfer
03 | 20 | IncomingTransfer
Logic:
SELECT SUM(amount)
IF IncomingTransfer
+ 230
+ 20
ELSE IF OutcomingTransfer
- 100
Total amount: +150
AS simple as my sqlfiddle shows:
select
sum(CASE WHEN type = 'IncomingTransfer' THEN amount ELSE -amount END) as totalsum
from t;
SELECT SUM(amount) FROM (
SELECT CASE WHEN type='IncomingTransfer'
THEN +amount
ELSE -amount
END as amount
FROM MyTable
) as data
I would use:
SELECT Amount = SUM(CASE WHEN Type = 'OutcomingTransfer' then (Amount*-1)
ELSE Amount END)
FROM <Table>
GROUP BY <Grouping Field>

Multiple Groupings with a sum

My Table :
ID | TIME OF CREATION | OWNER | STATE
1 2015-1-1 arpan A
2 2015-1-2 arpan B
My desired o/p from my query is :
DATE | OWNER | COUNT(STATE = A) | COUNT(STATE = B) | ...
I checked out SUM( CASE ) but you cant group by date and sum by owner right?
Stuck here. :(
Can someone help?
I think you just want conditional aggregation:
select date, owner, sum(case when state = 'A' then 1 else 0 end) as state_A,
sum(case when state = 'B' then 1 else 0 end) as state_b
from table t
group by date, owner;

Oracle 8i Query Help

I have a table that looks something like this:
ID | STATUS | TYPE
----------------------------------------
x123 | A | High School
x122 | I | High School
x124 | F | High School
x125 | A | College
x126 | I | College
x127 | F | College
x128 | F | College
Can anyone help me come up with a query for oracle 8i that displays this table like this
Type | Count A | Count I | Count F
------------------------------------------------------------
High School | 1 | 1 | 1
College | 1 | 1 | 2
Thanks!
Here's one approach:
select t.type as "Type"
, sum(case when t.status = 'A' then 1 else 0 end) as "Count A"
, sum(case when t.status = 'I' then 1 else 0 end) as "Count I"
, sum(case when t.status = 'F' then 1 else 0 end) as "Count F"
from my_table t
group by t.type
order by t.type desc
This works if you have specific columns you want returned, and works for "counting" rows that meet more complex criteria set.
[EDIT]
(Added the DESC keyword to get the result set ordered as shown by OP, +1 good catch by Rob van Wijk!)
(Andomar makes a good observation, with more and more columns in the result set, using this approach, the statement gets unweildy. There are other approaches to getting the same result set which work well if the only "test" is an equality comparison on a single column.)
Oracle 8i does support the CASE expression, doesn't it? Oracle 8 didn't, if I recall correctly. We can go "old school" to do the same thing with the DECODE function:
select t.type as "Type"
, sum(decode(t.status,'A',1,0)) as "Count A"
, sum(decode(t.status,'I',1,0)) as "Count I"
, sum(decode(t.status,'F',1,0)) as "Count F"
from my_table t
group by t.type
order by t.type DESC
[/EDIT]
Sometimes, we want to check more than one type condition, and include a row in more than one count. We can get a total
select t.type as "Type"
, sum(case when t.status in ('A') then 1 else 0 end) as "Count A"
, sum(case when t.status in ('I') then 1 else 0 end) as "Count I"
, sum(case when t.status in ('F') then 1 else 0 end) as "Count F"
, sum(case when t.status in ('A','I') then 1 else 0 end) as "#AI"
, sum(decode(sign(t.foo-t.bar),1,1,0)) as "#foo>bar"
, sum(decode(sign(10.0-t.foo),1,1,0)) as "#foo<10"
from my_table t
group by t.type
order by t.type desc
(Just to point out, it's possible for a row to satisfy the specified criteria for multiple columns, and so it could be "counted" more than once. Sometimes, that's exactly what we want.)