SQL column sum and difference - sql

my table, I want to create three columns in single-column, reprinted now.
id | date | type | total
------ | ------ | ------ | -----
1 | 01.10.2016| Paypal | 50
2 | 03.10.2016| credit | 40
3 | 05.10.2016| Cash | 50
4 | 06.10.2016| payment| 100
5 | 07.10.2016| Cash | 20
6 | 15.10.2016| Skrill | 10
7 | 18.10.2016| payment| 20
8 | 19.10.2016| Paypal | 10
9 | 19.10.2016| payment| 20
10 | 22.10.2016| Cash | 40
11 | 23.10.2016| Skrill | 10
my table, I want to create three columns in single-column, reprinted now.
SELECT id,date,type,total
(select (
sum(case when type="Paypal" then total else 0 end)+
sum(case when type="credit" then total else 0 end))+
sum(case when type="Cash" then total else 0 end) ) as receiv,
(Select(
sum(case when type="payment" then total else 0 end)) AS payment,
(Select sum(receiv -payment) FROM totals t2
WHERE (t2.date <= t1.date) and (t2.id <= t1.id) order by t1.date) AS remainder
FROM totals t1
group by date, type
order by id,date
--
The following query for the sql code?
Type = "Paypal, credit, Cash" sums "receiv" sums and Type = "payment" sums will be added to the "remainder" column.
id | date | type | receiv| payment| remainder
------ | ------ | ------ | ------| ------ | ------
1 | 01.10.2016| Paypal | 50 | 0 | 50
2 | 03.10.2016| credit | 40 | 0 | 90
3 | 05.10.2016| Cash | 50 | 0 | 140
4 | 06.10.2016| payment| 0 | 100 | 40
5 | 07.10.2016| Cash | 20 | 0 | 60
6 | 15.10.2016| Skrill | 10 | 0 | 70
7 | 18.10.2016| payment| 0 | 20 | 50
8 | 19.10.2016| Paypal | 10 | 0 | 60
9 | 19.10.2016| payment| 0 | 20 | 40
10 | 22.10.2016| Cash | 40 | 0 | 80
11 | 23.10.2016| Skrill | 10 | 0 | 90

Running total is easier in other databases which have analytical functions. In MySQL, you can do this with a correlated sub-query.
select id,dt,type,
case when type <> 'payment' then total else 0 end receiv,
case when type = 'payment' then total else 0 end payment,
case when type <> 'payment' then total else 0 end
- case when type = 'payment' then total else 0 end
+ coalesce((select sum(case when type <> 'payment' then total else 0 end)
- sum(case when type = 'payment' then total else 0 end)
from yourtable where id < y.id),0)
from yourtable y
Sample Demo

Related

How to get count based on Values in SQL

I've something to execute I need the count based on values. Here is my Table
"ORD_NUM","ORD_AMOUNT","ORD_DATE","CUST_CODE","AGENT_CODE","ORD_DESCRIPTION"
"200118"|"500"|"07/20/2008"|"C00023"|"A006"|"SOD"
"200120"|"500"|"07/20/2008"|"C00009"|"A002"|"SOD"
"200129"|"1000"|"07/20/2008"|"C00024"|"A006"|"SOD"
"200127"|"1000"|"08/20/2008"|"C00015"|"A003"|"SOD"
"200128"|"500"|"08/20/2008"|"C00009"|"A002"|"SOD"
"200128"|"500"|"09/20/2008"|"C00009"|"A002"|"SOD"
"200128"|"1000"|"09/20/2008"|"C00009"|"A002"|"SOD"
"200128"|"1000"|"10/20/2008"|"C00009"|"A002"|"SOD"
In the order amount we only have either 1000 or 500. We need to return the data count of 500 and 1000 for each date. EX:
Date |1000Count|500Count
07/20/2008| 1 | 2
08/20/2008| 1 | 1
09/20/2008| 1 | 1
10/20/2008| 1 | 1
Thanks! to SlavaRozhnev
select
d,
count(case when amount = 500 then 1 end) count500,
count(case when amount = 1000 then 1 end) count1000
from test
group by d;
Gives Result :
+============+==========+===========+
| d | count500 | count1000 |
+============+==========+===========+
| 2023-01-01 | 4 | 2 |
| 2023-01-02 | 1 | 1 |
| 2023-01-03 | 0 | 1 |
| 2023-01-04 | 1 | 0 |
+------------+----------+-----------+

SQL "Group" and "Count" categories

Edit. This is a follow up from another question. To simplify the question. Assume a table
date | id | type
01/01 | 1 | F
02/01 | 1 | F
02/01 | 1 | F
03/01 | 1 | S
03/01 | 1 | S
04/01 | 1 | F
04/01 | 1 | S
05/01 | 1 | S
I am looking for a way to summarise the above table by combination of transaction types per day. If a person (id) has only one transaction per day it counts as a Single type. If they have more than one it counts as a Multiple one. I've done that with my original query and it works. The output from the above table would be:
date | Single | Multiple
01/01 | 1 | 0
02/01 | 0 | 1
03/01 | 0 | 1
04/01 | 0 | 1
05/01 | 1 | 0
I got that far and it works. What's I'm struggling with (ie. don't have a clue of how to start) is how set up a query to show all possible combinations of Type (SS, FF, FS) instead of just counting the multiple transactions. The desired output would be like:
date | Single | # FF | # FS | # SS
01/01 | 1 | 0 | 0 | 0
02/01 | 0 | 1 | 0 | 0
03/01 | 0 | 0 | 0 | 1
04/01 | 0 | 0 | 1 | 0
05/01 | 1 | 0 | 0 | 0
Any constructive hints or ideas will be much appreciated.
this is assuming that you have max 2 types per date.
You can use the CASE WHEN statement with MIN() and MAX() to check for combination of FF, FS or SS
select [date],
case when count(*) = 1 then 1 else 0 end as Single,
case when count(*) >= 2
and min([type]) = 'F'
and max([type]) = 'F'
then 1
else 0
end as [# FF],
case when count(*) >= 2
and min([type]) = 'F'
and max([type]) = 'S'
then 1
else 0
end as [# FS],
case when count(*) >= 2
and min([type]) = 'S'
and max([type]) = 'S'
then 1
else 0
end as [# SS]
from yourtable
group by [date]
EDIT :
for more then 3 types, just change the count(*) = 2 to count(*) >= 2 as long as the type are either F or S

Sql : Based on column value do sum/substract

I am having data in sqltable like below :
+----+-------+-------------+--------+
| Id | PayId | DeductionId | Amount |
+----+-------+-------------+--------+
| 1 | 1 | 0 | 100 |
| 2 | 2 | 0 | 250 |
| 1 | 0 | 3 | 50 |
| 2 | 0 | 4 | 75 |
+----+-------+-------------+--------+
So in output, need group by on Id and when PayId is non-zero then do sum of amount and when DedctionId is non-zero then do sum of amount and substract of those two values. So need Output like below :
+----+--------+
| Id | Amount |
+----+--------+
| 1 | 50 |
| 2 | 175 |
+----+--------+
How to do that?
Hopefully, both are never non-zero. You just want conditional aggregation:
select id,
sum(case when payid > 0 then amount
when deductionid > 0 then - amount
else 0
end) as amount
from t
group by id;
Use a CASE statement for the SUM:
select
Id,
sum(
case when payid <> 0 then amount else 0 end -
case when deductionid <> 0 then amount else 0 end
) Amount
from tablename
group by id
See the demo.
Results:
> Id | Amount
> -: | -----:
> 1 | 50
> 2 | 175
A simple case expression should work here for you.
select Id
, Amount = sum(case when PayID > 0 then Amount else Amount * -1 end)
from YourTable
group by Id

SQL sum total each column in last row

I wish SQL for SUM each column(IPO and UOR) in TOTAL in second last. And GRAND TOTAL(Sum IPO + UOR) in the last one. Thank you so much
No Code IPO UOR
----------------------
1 D173 1 0
2 D176 3 0
3 D184 1 1
4 D185B 1 0
5 D187 1 2
6 F042 3 0
7 ML004 12 3
8 TTPMC 2 0
9 Z00204 1 0
------------------
TOTAL (NOS) 25 6
-------------------------
GRAND TOTAL (NOS) 31
Here is my code, :
SELECT
SUM(CASE WHEN IPOType = 'IPO' THEN 1 ELSE 0 END) as IPO,
SUM(CASE WHEN IPOType = 'UOR' THEN 1 ELSE 0 END) as UOR
FROM IPO2018
GROUP BY OriProjNo
it can show like this
No Code IPO UOR
----------------------
1 D173 1 0
2 D176 3 0
3 D184 1 1
4 D185B 1 0
5 D187 1 2
6 F042 3 0
7 ML004 12 3
8 TTPMC 2 0
9 Z00204 1 0
------------------
Generally speaking, you want to leave totals and sub-totals to whatever tool you are presenting your data in, as they will be able to handle the formatting with significantly more ease. In addition, your desired output does not have the same number of columns (Grand Total row only has one numeric) so even if you did shoehorn this in to the same dataset, the column headings wouldn't make sense.
That said, you can return group totals via the with rollup statement. This will provide an additional row with the aggregate totals for the group. Where there is more than one group in your data, you will get a sub-total row for each group and a total row for the entire dataset:
declare #t table(c nvarchar(10),t nvarchar(3));
insert into #t values ('D173','IPO'),('D176','IPO'),('D176','IPO'),('D176','IPO'),('D184','IPO'),('D184','UOR'),('D185B','IPO'),('D187','IPO'),('D187','UOR'),('D187','UOR'),('F042','IPO'),('F042','IPO'),('F042','IPO'),('TTPMC','IPO'),('TTPMC','IPO'),('Z00204','IPO'),('ML004','UOR'),('ML004','UOR'),('ML004','UOR'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO'),('ML004','IPO');
select row_number() over (order by grouping(c),c) as n
,case when grouping(c) = 1 then 'TOTAL (NOS)' else c end as c
,sum(case when t = 'IPO' then 1 else 0 end) as IPO
,sum(case when t = 'UOR' then 1 else 0 end) as UOR
from #t
group by c
with rollup
order by grouping(c)
,c;
Output:
+----+-------------+-----+-----+
| n | c | IPO | UOR |
+----+-------------+-----+-----+
| 1 | D173 | 1 | 0 |
| 2 | D176 | 3 | 0 |
| 3 | D184 | 1 | 1 |
| 4 | D185B | 1 | 0 |
| 5 | D187 | 1 | 2 |
| 6 | F042 | 3 | 0 |
| 7 | ML004 | 12 | 3 |
| 8 | TTPMC | 2 | 0 |
| 9 | Z00204 | 1 | 0 |
| 10 | TOTAL (NOS) | 25 | 6 |
+----+-------------+-----+-----+

Return all records if more than 2/3 satisfy a value

I have a table representing multiple transactions by customers in any given day. I need to return all transactions per customer if two thirds or more of the transactions per customer were cash instead of credit card.
In the example below I want to return all of customers' 1, 4 transactions as they were the only customers to have 2 thirds or more of their transactions as cash:
+----------------+-------------+-----------------+------------------+
| Transaction ID | CustomerNum | TransactionType | TransactionValue |
+----------------+-------------+-----------------+------------------+
| 1 | 1 | Cash | 11 |
| 2 | 1 | Card | 12 |
| 3 | 1 | Cash | 13 |
| 4 | 2 | Cash | 14 |
| 5 | 2 | Card | 15 |
| 6 | 3 | Cash | 15 |
| 7 | 3 | Card | 11 |
| 8 | 3 | Cash | 12 |
| 9 | 3 | Card | 13 |
| 10 | 4 | Cash | 14 |
| 11 | 4 | Cash | 15 |
| 12 | 4 | Cash | 15 |
+----------------+-------------+-----------------+------------------+
This seems to work with the sample data:
declare #t table (TranID int not null,CustomerNum int not null,
TranType varchar(17) not null,TranValue decimal(18,0) not null)
insert into #t(TranID,CustomerNum,TranType,TranValue) values
( 1,1,'Cash',11), ( 2,1,'Card',12), ( 3,1,'Cash',13),
( 4,2,'Cash',14), ( 5,2,'Card',15),
( 6,3,'Cash',15), ( 7,3,'Card',11), ( 8,3,'Cash',12), ( 9,3,'Card',13),
(10,4,'Cash',14), (11,4,'Cash',15), (12,4,'Cash',15)
;With Counted as (
select *,
COUNT(*) OVER (PARTITION BY CustomerNum) as cnt,
SUM(CASE WHEN TranType='Cash' THEN 1 ELSE 0 END)
OVER (PARTITION BY CustomerNum) as cashcnt
from #t
)
select * from Counted
where cashcnt * 3 >= cnt * 2
I've gone with simple multiplication at the end to keep all of the maths as integers and avoid having to think about float/decimal and the representation of 2/3.
Result:
TranID CustomerNum TranType TranValue cnt cashcnt
----------- ----------- ----------------- ----------- ----------- -----------
1 1 Cash 11 3 2
2 1 Card 12 3 2
3 1 Cash 13 3 2
10 4 Cash 14 3 3
11 4 Cash 15 3 3
12 4 Cash 15 3 3
Try this:
select t.*
from (select customernum
from transactions
group by customernum
having sum(case when TransactionType = 'Cash' then 1.0 else 0.0 end) / sum(1.0) > 0.6666) c
join transactions t on t.customernum = c.customernum