Display output is columns based on filter criteria - sql

I am trying to display data is columns/subcolumns based on certain filter criteria using case when statement but not getting required output.
data:
ID ID2 Country Type
1 001 US A
1 009 US A
2 002 AU B
3 003 CA A
3 005 CA A
4 007 US B
5 001 FR B
6 003 US B
7 002 US A
8 004 NZ A
based on my current case statement, here is how my output looks:
Type Country Count
B Other 2
B US 1
B Subtotal 3
A Other 4
A US 3
A Subtotal 7
Total 10
I want to display the following format, bonus if I can get the subtotal/totals:
Type-A Type-B
US Other US Other
3 4 1 2
I also need Subtotals, and Grandtotals, but these need to be calculated separately.
SubTotal: 7 SubTotal: 3
Grand Total: 10

You can like this
select
sum(case when Type = 'A' and Country = 'US' then 1 else 0 end) as US_TYPE_A,
sum(case when Type = 'A' and Country != 'US' then 1 else 0 end) as Other_TYPE_A,
sum(case when Type = 'B' and Country = 'US' then 1 else 0 end) as US_TYPE_B,
sum(case when Type = 'B' and Country != 'US' then 1 else 0 end) as Other_TYPE_B
from myTable

Related

Group by one column and return several columns on multiple conditions - T-SQL

I have two tables which I can generate with SELECT statements (joining multiple tables) as follows:
Table 1:
ID
Site
type
time
1
Dallas
2
01-01-2021
2
Denver
1
02-01-2021
3
Chicago
1
03-01-2021
4
Chicago
2
29-11-2020
5
Denver
1
28-02-2020
6
Toronto
2
11-05-2019
Table 2:
ID
Site
collected
deposited
1
Denver
NULL
29-01-2021
2
Denver
01-04-2021
29-01-2021
3
Chicago
NULL
19-01-2020
4
Dallas
NULL
29-01-2019
5
Winnipeg
13-02-2021
17-01-2021
6
Toronto
14-02-2020
29-01-2020
I would like the result to be grouped by Site, having on each column the COUNT of type=1 , type=2, deposited and collected, all of the 4 columns between a selected time interval. Example: (interval between 01-06-2020 and 01-06-2021:
Site
type1
type2
deposited
collected
Dallas
0
1
0
0
Denver
1
0
2
1
Chicago
1
1
0
0
Toronto
0
0
0
0
Winnipeg
0
0
1
1
How about union all and aggregation?
select site,
sum(case when type = 1 then 1 else 0 end) as type_1,
sum(case when type = 2 then 1 else 0 end) as type_2,
sum(deposited) as deposited, sum(collected) as collected
from ((select site, type, 0 as deposited, 0 as collected
from table1
) union all
(select site, null,
(case when deposited is not null then 1 else 0 end),
(case when collected is not null then 1 else 0 end)
from table2
)
) t12
group by site;
Combine your tables 1 and 2 with a join on Site
Use COUNT(CASE WHEN type = 1 then 1 END) as type1 and a similar construct for type 2
Use COUNT(CASE WHEN somedate BETWEEN '2020-06-01' and '2021-06-01' then 1 END) as ... for your dates

CASE function for multiple instances

I am looking to return a table with each column tagging whether or not a user used a certain product in a given month. The data appears as below:
User Date Product
001 1/1/2019 A
001 1/1/2019 A
001 1/1/2019 B
002 1/1/2019 A
002 1/1/2019 A
003 1/1/2019 C
004 1/1/2019 A
004 1/1/2019 B
004 1/1/2019 C
I would like the SQL code to result in this (i.e. a column for each product type, with a 1 or 0 if that product appeared in the row in the data):
User A B C
001 1 1 0
002 1 0 0
003 0 0 1
004 1 1 1
Currently I only end up with only a single 1 in each column, even when multiple instances exist. (This is in SQL Server)
Thanks!
You can use conditional aggregation:
select user,
max(case when product = 'A' then 1 else 0 end) as a,
max(case when product = 'B' then 1 else 0 end) as b,
max(case when product = 'C' then 1 else 0 end) as c
from t
group by user

Limit sql query to only rows where aggregate of col = 0

I'm looking at auction data in the following form:
product auction_id bid_value is_winning_bid reject_reason
iPhone 123 5 1 0
iPhone 123 3 0 1
iPhone 123 2 0 200
iPad 456 1 0 1
iPad 456 10 0 1
iPhone 789 2 0 200
iPhone 999 10 0 1
I want to count the number of auctions where one of the bids had a reject_reason = 200 and none of the bids has a is_winning_bid = 1, grouped by product.The data set is large so I don't want to have the output grouped by auction_id.
The table above should result in:
product total_auctions count_unfilled_auctions count_unfilled_auctions_200
iPhone 3 2 1
iPad 1 1 0
I think you just need two levels of aggregation, one at the auction level and one at the product level:
select product, count(*) as total_auctions,
sum(1 - has_winning_bid) as unfulfilled_auctions,
sum(case when cnt_reject_200 > 0 and has_winning_bid = 1 then 1 else 0 end) as unfulfilled_auctions_200
from (select auction_id, product,
max(is_winning_bid) as has_winning_bid,
sum(case when reject_reason = 200 then 1 else 0 end) as cnt_reject_200
from auctiondata ad
group by auction_id, product
) ad
group by product;

Unable to figure out Inventory current stock calculation

I have 2 tables whose structure is as follows:
tblBookMst
Id bk_isbn bk_title bk_author
----------------------------------------------------
1 ISBN_001 ABC Book AA
2 ISBN_002 DEF Book BB
3 ISBN_003 GHI Book CC
4 ISBN_004 JKL Book DD
and
tblBookId
b_id id lib_id inv_stat
----------------------------------------------------
1 1 BK/LIB/01 1
2 1 BK/LIB/02 2
3 1 BK/LIB/03 2
4 2 BK/LIB/04 1
5 2 BK/LIB/05 1
6 3 BK/LIB/06 1
('inv_stat' legends: 1=> In Stock & 2 => In Circulation)
Using the above 2 tables, i want to write a query which will give me output as shown below
bk_title bk_author tot_copies in_stock in_circulation
ABC Book AA 3 1 2
DEF Book BB 2 2 0
GHI Book CC 1 1 0
Till now i have been unable to figure out how to calculate the 'in_stock' & 'in_circulation'.I am using the below mentioned sql query.
SELECT a.id,a.bk_title,a.bk_author,count(b.lib_id) as tot_copies
FROM tblBookMst a
JOIN tblBookId b ON a.id = b.id
GROUP BY a.id,a.bk_title,a.bk_author
ORDER BY a.bk_title
I hope you understand my question.Please advice with example
You are close! You just need some Case Statements:
SELECT a.id,
a.bk_title,
a.bk_author,
count(b.lib_id) as tot_copies
SUM(CASE WHEN b.inv_stat = 1 THEN 1 ELSE 0 END) as in_stock,
SUM(CASE WHEN b.inv_stat = 2 THEN 1 ELSE 0 END) as in_circulation
FROM tblBookMst a
JOIN tblBookId b ON a.id = b.id
GROUP BY a.id,a.bk_title,a.bk_author
ORDER BY a.bk_title

Conditional Row Deleting in SQL

I have a table that contains 4 columns. I need to remove some of the rows based on the Code and ID columns. A code of 1 initiates the process I'm trying to track and a code of 2 terminates it. I would like to remove all rows for a specific ID when a code of 2 comes after a code of 1 and there is not an additional code 1. For example, my current data set looks like this:
Code Deposit Date ID
1 $100 3/2/2016 5
2 $0 3/1/2016 5
1 $120 2/8/2016 5
1 $120 3/22/2016 4
2 $70 2/8/2016 3
1 $120 1/3/2016 3
2 $0 6/15/2015 2
1 $120 3/22/2016 2
1 $50 8/15/2015 1
2 $200 8/1/2015 1
After I run my script I would like it to look like this:
Code Deposit Date ID
1 $100 3/2/2016 5
2 $0 3/1/2016 5
1 $120 2/8/2016 5
1 $120 3/22/2016 4
1 $50 8/15/2015 1
2 $200 8/1/2015 1
In all I have about 150,000 ID's in my actual table but this is the general idea.
You can get the ids using logic like this:
select t.id
from t
group by t.id
having max(case when code = 2 then date end) > min(case when code = 1 then date end) and -- code 2 after code 1
max(case when code = 2 then date end) > max(case when code = 1 then date end) -- no code 1 after code2
It is then easy enough to incorporate this into a query to get the rest of the details:
select t.*
from t
where t.id not in (select t.id
from t
group by t.id
having max(case when code = 2 then date end) > min(case when code = 1 then date end) and -- code 2 after code 1
max(case when code = 2 then date end) > max(case when code = 1 then date end)
);
The approach I took was to add up the Code per each ID. If it equals 3 exactly, it should be removed.
;WITH keepID as (
Select
ID
,SUM(code) as 'sumCode'
From #testInit
Group by ID
HAVING SUM(code) <> 3
)
Select *
From #testInit
Where ID IN (Select ID from keepID)
Your post showed keeping ID = 1 which does not seem to fit the criteria ? Are you sure you would be keeping ID = 1 ? It only as 2 records with a code of 1 and a code of 2 which adds up to 3 ... thus, remove it.
I just showed the approach in logic ... let me know if you need help with the delete code.
delete from table
where table.id in
(select id from B where A.id=B.id and B.date>A.date
from
(select code,id,max(date),id where code=1 group by id) as A,
(select code ,id,max(date),id where code=2 group by id) as B)
explanation: select code,id,max(date),id where code=1 as A
will fetch data with the highest date for a specific id of code 1
select code ,id,max(date),id where code=2 group by id) as B
will fetch data with the highest date for a specific id of code 2
select id from B where A.id=B.id and B.date>A.date wil select all the ids for which the code 2 date is higher than code 1 date.