SQL- Calculating SUM/COUNT with rows of table - sql

I have a PriceComparison table with (StoreNumber, ItemNumber, Price) that keeps pricing data for head-to-head comparison shopping. The goal is a recordset with the following things for all stores:
StoreNumber
COUNT of head-to-head wins for that store
COUNT of head-to-head losses for that store
COUNT of head-to-head ties for that store
SUM of all item pricing for that store
SUM of all head-to-head competitor pricing for items above for that store
Example:
StoreNumber ItemNumber Price
----------- ---------- -----
101 1 1.39
102 1 1.89
101 2 3.49
103 2 2.99
101 3 9.99
104 3 9.99
I'm thinking I can calculate these SUMs and COUNTs if I can get a temporary column added for CompetitorPrice. That way, the item has both prices listed, and it becomes easy.
How can I get this information in the correct configuration? I tried an INNER JOIN to the same table, but that gets tricky.
Thanks!
UPDATE: This is for MS SQL Server.
UPDATE: There will only be two prices per item, no more than 2 stores.

SELECT
a.storenumber,
SUM(CASE WHEN a.price < b.price THEN 1 ELSE 0 END) AS wins,
SUM(CASE WHEN a.price > b.price THEN 1 ELSE 0 END) AS losses,
SUM(CASE WHEN a.price = b.price THEN 1 ELSE 0 END) AS ties,
SUM(a.price) AS store_price_sum,
SUM(b.price) AS competitor_price_sum
FROM
pricecomparison a
INNER JOIN
pricecomparison b ON
a.itemnumber = b.itemnumber AND
a.storenumber <> b.storenumber
GROUP BY
a.storenumber

Related

Finding an Item based on certain criteria in 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;

T-SQL - Pivot out Distinct N rows for each group

I have a table similar to the one below with customers, products, and purchase date. I am trying to get a list of customers and their 3 most recently purchased DISTINCT products. I want to use purchase date as a means of ordering the results, but I don't want to see duplicate product IDs.
Customer
Product
PurchaseDate
1
a
2020-12-5
2
b
2020-12-5
1
a
2020-12-4
2
a
2020-12-3
1
b
2020-12-2
2
b
2020-12-1
1
c
2020-11-30
1
d
2020-11-29
2
b
2020-11-28
Ideally I would see results like this
Customer
Product1
Product2
Product3
1
a
b
c
2
b
a
I have tried partition by statements and order by statements, but everything wants me to include date in the final output. Is there a way to do this?
Most recent distinct products is tricky. This requires one level of aggregation per customer and product and then another for pivoting:
select customer,
max(case when seqnum = 1 then product end) as product_1,
max(case when seqnum = 2 then product end) as product_2,
max(case when seqnum = 3 then product end) as product_3
from (select customer, product, max(purchasedate) as max_purchasedate,
row_number() over (partition by customer order by max(purchasedate) desc) as seqnum
from t
group by customer, product
) cp
group by customer;

Summary Statistics for different categories using hive

I have below two hive tables called a and b. I need to create descriptive summary stats for it.
Now I want to calculate the summary statistics like below:
Expected output
Sum of Amount Count Sum of Fraud Amount Count of Fraud
0-100 120 2 70 1
100-500 610 3 410 2
>500 1300 2 700 1
Where I need Sum of Amount and count by categories mentioned like 0-100, 100-500 and >500.
Second i also need Sum of fraud amount (Where Fraud = 1) and count of frauds.I need to left join to get fraud column to calculate it.
e.g Category 0-100, The sum of amount is 120 (50+70) and count is 2. And Sum of fraud amount is 70 where fraud is 1. Similarly for others i need to calculate.
Table a
ID Amount Date
1 110 01-01-2020
2 200 02-01-2020
3 50 03-01-2020
4 600 04-01-2020
5 700 05-01-2020
6 70 06-01-2020
7 300 07-01-2020
Table b
ID Fraud
1 1
2 0
3 0
4 0
5 1
6 1
7 0
My Approach where i got overall count and Amount sum but i need category wise like, 0-100, 100-500, and >500
select sum(a.Amount), Count(*), count(b.Fraud)
from sample.data a
left join (select id, fraud from sample.label) b
on a.id = b.id
where date between "2020-01-01" and "2020-01-07"
group by fraud;
If I understand correctly, you just need to aggregate by a case expression:
select (case when d.amount <= 100 then '0-100'
when d.amount <= 500 then '101-500'
else '> 500'
end) as grp,
sum(d.Amount), Count(*), sum(l.Fraud)
from sample.data d left join
sample.label l
on a.id = l.id
where d.date between '2020-01-01' and '2020-01-07'
group by (case when d.amount <= 100 then '0-100'
when d.amount <= 500 then '101-500'
else '> 500'
end);

SQL Query to show all columns

I have the following table and a SQL query to determine if any items in a table have a buy price higher than a sell price.
Query:
SELECT id, name
FROM orders
GROUP BY id, name
HAVING MAX(CASE WHEN buy = 'false' THEN price END) > MIN(CASE WHEN buy = 'true' THEN price END)
The problem is that this only returns two rows:
The result I am looking for should show all the items that have a buy price higher than a sell price with all the columns. Reading up on GROUP BY I see that it only returns distinct values. Do I have to use joins to achieve the end result?
|id |buy |date |price |name
--------------------------------------------------
3 false 2017-01-04 19:23:12.000 7 bread
3 false 2017-01-04 19:23:12.000 4 bread
2 false 2017-01-04 19:23:12.000 7 grapes
Using this query the result is the table below the rows highlighted in red shouldn't be there.
SELECT *
FROM orders
WHERE id IN (SELECT id
FROM orders
GROUP BY id, name
HAVING MAX(CASE WHEN buy = 'false' THEN price END) > MIN(CASE WHEN buy = 'true' THEN price END))
Use your existing query as a subquery:
SELECT * from orders where id in
(
SELECT id
FROM orders
GROUP BY id, name
HAVING MAX(CASE WHEN buy = 'false' THEN price END) > MIN(CASE WHEN buy = 'true' THEN price END)
)

Oracle SQL: Insert based on found value in a column given condition from another table

I want to merge my order data into one table which is now in two separate tables:
Order ID and customer code in table Orders:
Order_ID Customer
1 C11
2 C76
4 C32
and order detalis in table Details (with columns Order_ID, Hour, Quantity) in which the ordered quantity for the hours that the order is valid is given:
Order_ID Hour Quantity
1 2 10
1 3 20
2 2 5
2 3 5
2 4 5
4 6 20
4 7 25
I want to merge data of these two tables in one table to have only one row per each order by inserting the quantity for the hours that the order is valid in corresponding column, otherwise zero.
Order_ID Cutomer Hour1 Hour2 Hour3 Hour4 Hour5 Hour6 Hour7 ...
1 C11 0 10 20 0 0 0 0
2 C76 0 5 5 5 0 0 0
4 C32 0 0 0 0 0 20 25
I tried (only for quantity of hour 1):
insert into Merged_Order_Table
(Order_ID,Customer,Hour1)
select
Orders.Order_id,Orders.Customer,
case
when 1 in (select Details.Hour from Details,Orders where
Details.Order_ID = Orders.Order_ID)
then Details.Quantity
else 0
end
from
Orders
inner join
Details
on
Details.Order_ID = Orders.Order_ID;
But got quantity in Hour1 even for orders with no quantity in this hour.
I question why you would want to take nicely normalized data and put it into a table with that structure. I can understand a query returning the data like that, but another table?
In any case, your problem is a common problem when using correlated subqueries. The table being correlated is included in the subquery. Ooops. Here is fix for that:
insert into Merged_Order_Table(Order_ID, Customer, Hour1)
select o.Order_id, o.Customer,
(case when 1 in (select d.Hour from Details d where d.Order_ID = o.Order_ID)
then d.Quantity
else 0
end)
from Orders o;
That said, what you really want is conditional aggregation:
insert into Merged_Order_Table(Order_ID, Customer, Hour1)
select o.Order_id, o.Customer,
sum(case when d.Hour = 1 then d.Quantity else 0 end)
from Orders o left join
Details d
on o.Order_ID = d.Order_ID
group by o.Order_id, o.Customer;
You are on a right track!
you just need one more layer:
select order_id, customer, max(quantity) hour1 from
(your query)
group by order_id, customer
Or you can look into how to do PIVOT tables