How to SQL SUM with condition - sql

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>

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

Get the credit and the debit from the transaction details using 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

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;

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;

Creating Columns for Summed Answers

So I'm trying to move my row info into the column - I haven't used a Pivot before and tried using it now but clearly I'm doing something wrong -.-;
Here is my original Query
(Select
CASE WHEN ee.ExpenseTypeID=1 THEN Sum(Amount)
WHEN ee.ExpenseTypeID=2 THEN Sum(Amount)
WHEN ee.ExpenseTypeID=3 THEN Sum(Amount)
WHEN ee.ExpenseTypeID=4 THEN Sum(Amount) END as Amount,
et.ExpenseDescription,
ee.UserID
From ExpensesEntries ee, ExpenseTypes et
Where ee.ExpenseTypeID=et.ExpenseTypeID
Group By ee.ExpenseTypeID, et.ExpenseDescription, ee.UserID
Order By UserID) b
Which produces something like this
Amount | ExpenseDescription | UserID
----------------------------------------
156.00 | Upload | 123
----------------------------------------
23.00 | Parking | 123
----------------------------------------
15.37 | Other | 123
----------------------------------------
112.00 | Other | 456
----------------------------------------
28.50 | Parking | 456
----------------------------------------
What I would like to do
UserID | Upload | Parking | Other
----------------------------------
123 | 156.00 | 23.00 | 15.37
----------------------------------
456 | NULL | 28.50 | 112.00
I tried doing this - which is the equivalent of slapping on a Pivot but with the Cases in my original select - I'm not sure if I need to get rid of them entirely and add it into Pivot ?
Select
CASE WHEN ee.ExpenseTypeID=1 THEN Sum(Amount)
WHEN ee.ExpenseTypeID=2 THEN Sum(Amount)
WHEN ee.ExpenseTypeID=3 THEN Sum(Amount)
WHEN ee.ExpenseTypeID=4 THEN Sum(Amount) END as Amount,
et.ExpenseDescription,
ee.UserID
From ExpensesEntries ee, ExpenseTypes et
Where ee.ExpenseTypeID=et.ExpenseTypeID
Group By ee.ExpenseTypeID, et.ExpenseDescription, ee.UserID
Order By UserID
PIVOT
(Amount
FOR et.ExpenseDescription IN ('Upload','Other','Parking')
) as pvt
You didn't provide details on what each of the ExpenseTypeId values relate to but you can do this using an aggregate function with a CASE expression. The CASE expression will check the value of the ExpenseTypeId and get a sum of the amount - you will then name the column with the ExpenseDescription:
select ee.UserId,
sum(case when ee.ExpenseTypeID=1 then Amount else 0 end) Upload,
sum(case when ee.ExpenseTypeID=2 then Amount else 0 end) Parking,
sum(case when ee.ExpenseTypeID=3 then Amount else 0 end) Other
from ExpensesEntries ee
inner join ExpenseTypes et
on ee.ExpenseTypeID=et.ExpenseTypeID
group by ee.UserId;
If you want to use PIVOT, then you would alter your query to something similar to the following. This uses a join between your 2 tables in a subquery and you return the UserId, ExpenseDescription and Amount. The PIVOT will sum the amount for each ExpenseDescription - this process converts the descriptions to columns:
select UserId, Upload, Other, Parking
from
(
select ee.UserId,
et.ExpenseDescription
Amount
from ExpensesEntries ee
inner join ExpenseTypes et
on ee.ExpenseTypeID=et.ExpenseTypeID
) d
pivot
(
sum(Amount)
for ExpenseDescription in (Upload, Other, Parking)
) p;