Finding an Item based on certain criteria in SQL - sql

I have the following table structure:
Transaction table:
code type action level id qty OrderID
====================================================
10005 PRODUCT RECIPE 0 0 1 O-123
821 VALUE_MEAL RECIPE 0 1 1 O-123
9 PRODUCT RECIPE 1 1 1 O-123
7093 PRODUCT RECIPE 1 1 1 O-123
10005 PRODUCT CHOICE 1 1 1 O-123
721 VALUE_MEAL RECIPE 0 2 1 O-123
9 PRODUCT RECIPE 1 2 1 O-123
7093 PRODUCT RECIPE 1 2 1 O-123
10005 PRODUCT CHOICE 1 2 1 O-123
My Master table:
code FullName MenuCategory
---------------------------------
821 ML2 Group2
721 ML1 Group2
9 fires Group2
10005 Orange Group3
Expected result set:
code QTY with Meal Sold Alone
------------------------------------
10005 2 1
In the expected result, we need to differentiate if an item code "10005" was sold with a VALUE_MEAL that has different level and id or it was sold alone as a PRODUCT within the same order?
Example: Code=821, contains three main sub-level which are (9, 7093, 10005) and code=721, contains three main sub-level which are (9, 7093, 10005)
so here we know 2 QTY were sold for 10005 as it's part of both VALUE_MEALS and one QTY for code = 10005 as part of standalone product

It looks like you just want a grouped self-join, with conditional aggregation
SELECT
t.code,
[QTY with Meal] = COUNT(t2.IsMeal), -- only counts non nulls
[Sold Alone] = COUNT(*) - COUNT(t2.IsMeal)
FROM [Transaction] t
CROSS APPLY (
SELECT IsMeal = CASE WHEN COUNT(*) > 0 THEN 1 ELSE NULL END
FROM [Transaction] t2
WHERE t2.id = t.id
AND t2.type = 'VALUE_MEAL'
) t2
WHERE t.code = 10005
GROUP BY
t.code;
You could also switch the COUNT(*) in the subquery for an EXISTS

For each (OrderID, code) unique pair, the query uses the 'level' column to determine whether or not items have been combined in a meal
select OrderID, code,
sum(case when [level]>0 then 1 else 0 end) [QTY with Meal],
sum(case when [level]=0 then 1 else 0 end) [Sold Alone]
from TransactionTable
group by OrderID, code
order by OrderID, code;

Related

SQL Group by Sales Rep - Select 2 counts

I would like to query a table that has leads assigned by sales rep to return the unique number of leads grouped by agent and also the number sold. There can be multiple leads from one buyer, I would like to select distinct so each buyer is counted only once. Here is the layout of the data:
AgentId
BuyerEmail
Product
Category
1
lisa#gmail.com
Jeans
1
1
lisa#gmail.com
Hat
1
1
ryan#gmail.com
Shoes
3
2
mark#gmail.com
Jeans
1
2
mark#gmail.com
Socks
1
2
mark#gmail.com
Hat
1
4
john#gmail.com
Shirt
3
5
lou#gmail.com
Hat
3
5
tim#gmail.com
Shirt
3
I would like to return a dataset like the following:
AgentId
UniqueLeads
QtySold
1
2
1
2
1
0
4
1
1
5
2
2
I can query this individually but I can't get it to return in one result set. Here are the 2 separate queries:
SELECT COUNT(DISTINCT BuyerEmail) FROM SalesLeads GROUP BY InitialAgent
SELECT COUNT(DISTINCT BuyerEmail) FROM SalesLeads WHERE Category = 3 GROUP BY InitialAgent
How can I query the table and have both data points return in one result set? Please note, a category = 3 means it is sold.
You can use conditional aggregation to calculate QtySold in the same statement:
select AgentId,
count(distinct BuyerEmail) as UniqueLeads,
count(case when Category = 3 then Category end) as QtySold
from SalesLeads
group by AgentId
When Category is anything other than 3 the case statement returns null so that record isn't counted in the QtySold calculation.
db<>fiddle

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

Group by with set of values in PostgreSQL

I have a product table:
productid product
1 A-110
2 B-110
3 C-400
4 D-401
And orderditems table:
orderitemid productid qty
1 1 10
2 2 10
3 3 10
4 3 10
5 4 10
I can group by based on product as:
select productid, sum(qty)
from ordereditems
group by productid
Which gives:
1 10
2 10
3 20
4 10
However for this query productid 1 & 2 , 3 & 4 are the same.
Meaning that I want to see:
1 + 2 20
3 + 4 30
Basically I want the query to understand that 1 & 2 are the same group and 3 & 4 are the same group.
How can i do that?
Edit:
Products 1 & 2 , 3 & 4 are not the same. However they are of the same family... What I want is to see how much we sell per family and not per product.
This is why the desired out put is:
1 + 2 20
3 + 4 30
A hacky version if you know that 1&2 are the same and 3&4 are the same, and those are the only things the same.
select
case
when productid in (1,2) then '1 + 2'
when productid in (3,4) then '3 + 4'
else productid
end as product_ids, sum(qty)
from ordereditems
group by
case
when productid in (1,2) then '1 + 2'
when productid in (3,4) then '3 + 4'
else productid
end
A better approach is to record in the database that two products are the same. Either by linking the duplicated products (2,4) to the product they're the same as (1,3) or by creating a new table family etc. and recording that products 1,2 are related to the same family.
family
familyid name
1 1+2
2 3+4
Extend product table
productid product familyid
1 A-110 1
2 B-110 1
3 C-400 2
4 D-401 2
then you can group on family
select f.name, sum(qty)
from ordereditems oi
inner join product p on oi.productid = p.productid
inner join family f on p.familyid = f.familyid
group by f.name
Pls add a GroupID/Category field to your table.
productid product GroupID
1 A-110 A
2 B-110 A
3 C-400 B
4 D-401 B
Then use the query
select GroupID, sum(qty) as Sold
from ordereditems
group by GroupID
This will represent as group sale as if you have more than 10 products in a group your productid will make complicity to understand.
If it works for you pls mark as helpful.. :)

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
);

SQL Server : Joining two pivot tables

I'm trying to create join a table with itself. So for example below the table pivots based on the sum of D (Debits) and C (Credits) however I need to join the table with itself to add additional columns displaying count of an "D" entry and "C" plus two more additional columns showing the overall sum and overall count. How do I join the table below to create the additional columns?
Input table
GL_BU GL_Source GL_JE_Type GL_Amount Amount_Prefix
------------------------------------------------------------------
202 Payables Purchase Invoices 1234 C
202 Payables Purchase Invoices 123 D
202 Inventory Inventory 123 C
202 Payables Purchase Invoices 1234 C
Output Table
GL_BU GL_Source GL_JE_Type Amount D Amount C Count D Count C Total Count Total Amount
------------------------------------------------------------------------------------------
202 Spreadsheet XXXXX 1234 123 1 1 2 1357
202 Manual XXXXX 1234 123 2 2 4 1357
202 Manual XXXXX 1234 123 1 1 2 1357
202 Inventory XXXXX 1234 123 4 4 8 1357
202 Sales Order XXXXXX 1234 123 1 1 2 1357
Current Code
SELECT *
FROM
(SELECT
[GL_Business_Unit]
,[GL_Source]
,[GL_JE_Type]
,([GL_Amount])
,[Amount_Prefix]
FROM [03_rdm].[table_2013]) as t
Pivot(SUM([GL_Amount])
FOR [Amount_Prefix] IN (D,C)) AS pvt1
Current code link in SQLFiddle http://sqlfiddle.com/#!3/92369/2
Your sample data doesn't match your desired result so I'm guessing that this is what you need. You could use a PIVOT to get the result, but it seems that this would be much easier to get this using an aggregate function and some conditional logic via a CASE expression:
select
GL_BU,
GL_Source,
GL_JE_Type,
sum(case when Amount_Prefix = 'D' then GL_Amount else 0 end) Amount_D,
sum(case when Amount_Prefix = 'C' then GL_Amount else 0 end) Amount_C,
sum(case when Amount_Prefix = 'D' then 1 else 0 end) Count_D,
sum(case when Amount_Prefix = 'C' then 1 else 0 end) Count_C,
count(*) TotalCount,
sum(GL_Amount) TotalAmount
from table_2013
group by GL_BU, GL_Source, GL_JE_Type;
See SQL Fiddle with Demo