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

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

Related

SQL count where where column is greater than the other in group by?

Suppose I have a table money_table like:
team_id | money_spent | money_budget
--------------------------------------
123 | 3456.32 | 3466
964 | 236.32 | 200
123 | 9663 | 9400
964 | 3456.32 | 3466
The output table should be:
team_id | total_money_spent | total_money_budget | days_over_spent | days_under_spent
--------------------------------------
123 | 13119.32 | 12866 | 2 | 0
964 | 3692.64 | 3666 | 1 |. 1
The first 2 columns are easy with a group BY, I am wondering about the last 2 columns and how to tackle that. My initial query was:
SELECT
team_id,
SUM(money_spent) as total_money_spent,
SUM(money_budget) as total_money_budget
FROM money_table
GROUP BY team_id
ORDER BY team_id ASC
The works fine for the first 2 columns, but I am unable to think of how to get days_over_spent and days_under_spent.
Any suggestions?
Edit:
days_over_spent is the number of rows where money_spent > money_budget
days_under_spent is the number of rows where money_spent < money_budget
You could do the calculations for "over the budget" in a CTE
with tmp (t, s, b, o, u) as (
select
team,
spent,
budget,
case when spent > budget then 1 else 0 end,
case when spent < budget then 1 else 0 end
from budget
)
select
t as team,
sum(s) as total_spent,
sum(b) as total_budget,
sum(o) as days_over,
sum(u) as days_under
from tmp
group by t
Of course you can also just add the case into the query itself
select
team,
sum(spent),
sum(budget),
sum(case when spent > budget then 1 else 0 end),
sum(case when spent < budget then 1 else 0 end)
from budget
group by team
SELECT
team_id,
SUM(money_spent) as total_money_spent,
sum(money_budget) as total_money_budget,
sum(case when money_spent > money_budget then 1 else 0 end) as days_over_spent,
sum(case when money_spent < money_budget then 1 else 0 end) as days_under_spent
FROM money_table
GROUP BY team_id
ORDER BY team_id ASC

SQL Server: select count of rows with not empty fields and total count of rows

Table has 4 int columns (Price0, Price1, Price2, Price3).
Example of table:
ID | Price0 | Price1 | Price2 | Price3 |
---+--------+--------+--------+--------+
1 | 10 | 20 | NULL | NULL |
2 | 70 | NULL | NULL | NULL |
3 | 30 | 40 | 50 | NULL |
How to query this table to get
total count of rows
and count of rows where count of filled Price columns >= N (for example N = 2)
Result must be:
Total | Filled
------+-------
3 | 2
This query show how many Price fileds is filled in each row
select
(select count(*) as filledFieldsCount
from (values (T.Price0), (T.Price1), (T.Price2), (T.Price3)) as v(col)
where v.col is not null
)
from Table1 T
Wouldn't with only 4 columns a simple nested case when be straightforward
select count(*),
sum(case when (
CASE WHEN Price1 is null THEN 0 ELSE 1 END +
CASE WHEN Price2 is null THEN 0 ELSE 1 END +
CASE WHEN Price3 is null THEN 0 ELSE 1 END +
CASE WHEN Price4 is null THEN 0 ELSE 1 END) >= 2 then 1 else 0 end)
FROM Table1
You can do this with conditional aggregation:
select count(*),
sum(case when tt.filledFieldsCount >= 2 then 1 else 0 end)
from Table1 T outer apply
(select count(*) as filledFieldsCount
from (values (T.Price0), (T.Price1), (T.Price2), (T.Price3)) as v(col)
where v.col is not null
) tt;
I moved the subquery to the from clause using apply. This is an example of a lateral join. In this case, it does the same thing as the subquery.

Count who paid group by 1, 2 or 3+

I have a payment table like the example below and I need a query that gives me how many IDs paid (AMOUNT > 0) 1 time, 2 times, 3 or more times. Example:
+----+--------+
| ID | AMOUNT |
+----+--------+
| 1 | 50 |
| 1 | 0 |
| 2 | 10 |
| 2 | 20 |
| 2 | 15 |
| 2 | 10 |
| 3 | 80 |
+----+--------+
I expect the result:
+-----------+------------+-------------+
| 1 payment | 2 payments | 3+ payments |
+-----------+------------+-------------+
| 2 | 0 | 1 |
+-----------+------------+-------------+
ID 1: Paid 1 time (50). The other payment is 0, so I did not count. So, 1 person paid 1 time.
ID 2: Paid 3 times (10,20,15). So, 1 person paid 3 or more time.
ID 3: Paid 1 time (80). So, 2 persons paid 1 time.
I'm doing manually on excel right now but I'm pretty sure there is a more practical solution. Any ideas?
A little sub-query will do the trick
Declare #YOurTable table (ID int, AMOUNT int)
Insert into #YourTable values
( 1 , 50 ),
( 1 , 0) ,
( 2 , 10) ,
( 2 , 20) ,
( 2 , 15) ,
( 2 , 10) ,
( 3 , 80)
Select [1_Payment] = sum(case when Cnt=1 then 1 else 0 end)
,[2_Payment] = sum(case when Cnt=2 then 1 else 0 end)
,[3_Payment] = sum(case when Cnt>2 then 1 else 0 end)
From (
Select id
,Cnt=count(*)
From #YourTable
Where Amount<>0
Group By ID
) A
Returns
1_Payment 2_Payment 3_Payment
2 0 1
To get the output you want try using a table to form the data and then SELECT from that:
with c as (
select count(*) count from mytable where amount > 0 group by id)
select
sum(case count when 1 then 1 else 0 end) "1 Payment"
, sum(case count when 2 then 1 else 0 end) "2 Payments"
, sum(case when count > 2 then 1 else 0 end) "3 Payments"
from c
Here is an example you can play with to see how the query is working.

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>

Counting sum of items of type

What i what to do is from this :
|type|quantity|
+----+--------+
|shoe| 10 |
|hat | 2 |
|shoe| 7 |
|shoe| 1 |
|hat | 5 |
to get this :
|shoes|hats|
+-----+----+
| 18 | 7 |
How can i do that? So far I hadn't come up with a working query, I think it should look something like that:
SELECT
SUM(CASE type WHEN 'shoe' then quantity ELSE 0 END) AS "shoes",
SUM(CASE type WHEN 'hat' then quantity ELSE 0 END) AS "hats"
FROM items
GROUP BY type
Just drop the group by. You want only one row:
SELECT
SUM(CASE type WHEN 'shoe' then quantity ELSE 0 END) AS "shoes",
SUM(CASE type WHEN 'hat' then quantity ELSE 0 END) AS "hats"
FROM items ;