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

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;

Related

How to reset running counts and start from 1 based on the condition and make previous row values as 0 in SQL?

For example there is some table with below data:
No Id Value
1 100 1
2 100 0
3 100 1
4 100 2
1 101 1
2 101 2
1 102 0
2 102 1
I have to write SQL query, which will return row count based on specific condition. If the value matches 0 then need to reset running counts and start from 1 and make previous row values as 0
So the result will be like:
No Id Value Running Count
1 100 1 0
2 100 0 0
3 100 1 1
4 100 1 2
1 101 1 1
2 101 2 2
1 102 1 0
2 102 0 0
Your sample dataset is quite limited so I'm not sure of all edge cases but see if the following works for you. If not it might help get you there.
This gets a running count using a window & case expression and uses lead to check the next value.
If the current value or next value is 0 the count is 0, otherwise it's the running count subtracting 1 if there is a 0 in the Id block indicating the count was reset.
select No, Id, Value,
case when value = 0 or nv = 0
then 0
else
rc - case when Min(value) over(partition by id) = 0 then 1 else 0 end
end Running_Count
from (
select *,
Sum(case when value = 0 then 0 else 1 end) over(partition by id order by no) rc,
Lead(Value) over(partition by Id order by No)nv
from t
)t;

Show two different sum columns based on a single column

Show two different sum columns based on another column.
For this table:
ID Item Quantity Location
1 1 10 A
2 1 10 B
3 1 10 A
4 2 10 A
5 2 10 A
6 2 10 B
7 3 10 A
8 3 20 A
I need to see the total quantities for both location A and location B (to compare which is higher), but only for items that have a location B:
Expected result:
Item Quantity A Quantity B
1 20 10
2 20 10
I've been trying this but getting errors:
SELECT st.item, st.qty ALIAS(stqty),
(SELECT SUM(dc.qty)
FROM table dc
WHERE st.item = dc.item) ALIAS(dcqty))
FROM table st
WHERE location ='b'
I can do this easily with two queries obviously, but I was hoping for a way to do it in one.
you can use a sum with case statement to do your pivot then a having to exclude rows with no total for b
here is the fiddle
https://www.db-fiddle.com/f/rS8fgvWoFxn879Utc2CKbu/0
select Item,
sum(case when Location = 'A' then Quantity else 0 end),
sum(case when Location = 'B' then Quantity else 0 end)
from myTable
group by Item
having sum(case when Location = 'B' then Quantity else 0 end) > 0

SQL: calculation on two columns with multiple group by statements

I have a table which has the following columns:
user_id - includes duplicates
product_id - includes duplicates
purchases - number of purchases of given product_id
My table looks somewhat like this:
user_id date product_id purchases
0 1 1 1 4
1 1 2 1 0
2 1 3 2 0
3 1 4 2 0
4 2 1 1 1
5 2 2 1 0
6 2 3 1 1
7 3 1 2 0
8 3 2 3 0
9 4 1 5 1
My goal is to calculate the following metric:
% of products that were purchased at least once, grouped by user
For example: user 1 had 2 products, one of them got purchased at least once, the other one did not get purchased at all. So the metric would be the number of products that got purchased at least once / number of all products per user: 1/2 * 100 = 50%
I have little SQL experience so I do not have any legitimate code that could be corrected.
My desired output would be like this:
user_id total_products products_with_purchases metric
0 1 2 1 50%
1 2 1 1 100%
2 3 2 0 0%
3 4 1 1 100%
I would appreciate seeing a good practice solution to this problem. Many thanks!
select
user_id,
count(distinct product_id) as total_products,
count(distinct case when purchases > 0 then product_id end) as products_with_purchases,
100.00 * count(distinct case when purchases > 0 then product_id end)
/ count(distinct product_id) as metric
from T as t
group by user_id
https://rextester.com/EDSY39439
You can do this all in one query but this is the type of situation where it is easier to understand with sub-queries -- sql optimizer should make it fast.
select
user_id,
total_products,
products_with_purchase,
(products_with_purchase / total_products) * 100 as metric
from (
select -- group by user to get totals
user_id,
count(product_id) as total_products,
sum(case when purchases > 0 then 1 else 0 end) as products_with_purchase
from ( -- group by user and product and get purchase items
SELECT user_id, product_id, sum(purchases) as purchases
FROM table
GROUP BY user_id, product_id
) X
group by user_id
) X2
I Am Mohit Sahni
you can solve the above problem with the below SQL Code:
select
user_id,
count(distinct product_id) as total_products,
sum(case when purchases = 0 then 0 else 1 end) as products_with_purchases,
((sum(case when purchases = 0 then 0 else 1 end))/count(distinct product_id))*100 as metric
from
table
group by
user_id

Multiple times Grouping with where in SQL Server

I have a source table like this
ProductName SaleReceipt SaleCode
--------------------------------
F-Apple 1001 1
F-Orange 1002 2
G-Rice 1003 3
G-Barile 1005 4
G-Oats 1006 1
V-Carrot 1007 4
V-Cabbage 1008 3
V-Potato 1009 1
V-Tomato 1010 1
Chocolate 1011 4
Cookies 1012 1
Cakes 1013 2
I need to create a report like this
30 Day delay 60 Day Delay 90 day delay 120 day delay
Fruits 1 1 0 0
Grains 1 0 1 1
Vegetables 2 0 1 1
Other category 1 1 0 1
The conditions to create the report are:
All ProductName start with F is grouped as fruits
All ProductName start with G is grouped as Grains
All ProductName start with V is grouped as Vegetables
Other product name go in the other category
30 day delay: count of (SaleReceipt) with a SaleCode=1
60 day delay: count of (SaleReceipt) with a SaleCode=2
90 day delay: count of (SaleReceipt) with a SaleCode=3
120 day delay: count of (SaleReceipt) with a SaleCode>=4
I could not find how to do grouping two times. I am using SQL Server 2014.
You can use case in a group by. Or use a lookup table:
select coalesce(c.name, 'Other category'),
sum(case when salescode = 1 then 1 else 0 end) as salecode_1,
sum(case when salescode = 2 then 1 else 0 end) as salecode_2,
sum(case when salescode = 3 then 1 else 0 end) as salecode_3,
sum(case when salescode = 4 then 1 else 0 end) as salecode_4
from t left join
(values ('F-%', 'Fruit'), ('G-%' , 'Grain'), ('V-%', 'Vegetable')
) c(pattern, name)
on t.productname like c.pattern
group by coalesce(c.name, 'Other category');

SQL Query. limit an update per rows if condition is X and Y for the same ID number

Have the following table tblTrans where
Trans_ID Trans Sequence Trans_PointsEarned Trans_PointsApplied
4452 1 1 1
4452 2 1 1
4452 3 0 1
4462 1 1 1
4462 2 1 1
4462 3 1 1
4462 4 1 1
4462 5 1 1
9101 1 0 1
9101 2 0 1
9101 3 0 1
9101 4 0 1
(useless table doesnt work)
I need to set the following on another field per every customer ID.
So Customer_OverallPoints
4452 = 2 (doesn't count 0's)
4462 = 4 (I want to cap the points to 4 based on the sequence and transID and customerID)
9101 = 0 (dont count 0's).
This needs to be applied to thousands of records based on customerID and TransID where Trans_Sequence is within the same Trans_ID and it only counts the first 4 rows that have the Trans_pointsEarned = 1.
I tried putting a psuedocode together but it just looked ridicilous and I can't even come up with the logic for this.
Thanks
Assuming that TransId is really the customer id, I think the basic logic is just an aggregation:
select t.TransId,
(case when sum(t.Trans_PointsEarned) > 4 then 4
else sum(t.Trans_PointsEarned)
end) as Customer_OverallPoints
from tblTrans t
group by t.TransId;
You can put this into an update statement as:
update customers c
set Customer_OverallPoints = (select (case when sum(t.Trans_PointsEarned) > 4 then 4
else sum(t.Trans_PointsEarned)
end)
from tblTrans t
where t.TransId = c.CustomerId
);