Product Price at a Given Date from LeetCode - sql

What is wrong with my code?
QUESTION:
Table: Products: product_id | new_price | change_date
(product_id, change_date) is the primary key of this table.
Each row of this table indicates that the price of some product was changed to a new price at some date.
Write an SQL query to find the prices of all products on 2019-08-16. Assume the price of all products before any change is 10.
MY SOLUTION:
WITH cte1 AS (
SELECT product_id,
new_price AS price,
MAX(change_date) AS new_change_date
FROM Products
WHERE change_date <= CAST('2019-08-16' AS DATE)
GROUP BY product_id
),
cte2 AS (
SELECT product_id,
(new_price - 10) AS price,
MIN(change_date) AS new_change_date
FROM Products
WHERE change_date > CAST('2019-08-16' AS DATE)
GROUP BY product_id
)
SELECT DISTINCT product_id,
price
FROM cte1
UNION ALL
SELECT DISTINCT product_id,
price
FROM cte2
WHERE NOT EXISTS (SELECT product_id from cte1
WHERE cte2.product_id = cte1.product_id)
MY OUTPUT:
{"headers": ["product_id", "price"], "values": [[**1, 20**], [2, 50], [3, 10]]}
EXPECTED:
{"headers": ["product_id", "price"], "values": [[**1, 35**], [2, 50], [3, 10]]}

One method is union all. The first part fetches the most recent price as of the specified date. The second gets everything else:
select p.product_id, p.price
from products p
where change_date = (select max(p2.change_date)
from products p2
where p2.product_id = p.product_id and
p2.change_date <= '2019-08-16'
)
union all
select p.product_id, 10
from products p
where not exists (select 1
from products p2
where p2.product_id = p.product_id and
p2.change_date <= '2019-08-16'
);

Related

SQL: How to select the highest priced used item for each day

I need to produce a query that would give me the highest priced used product for each day where the total price of products sold that day exceeds 200.
SELECT *, max(price)
FROM products
WHERE products.`condition` = 'used' and products.price > 200
GROUP BY date_sold
Here is my products table http://prntscr.com/of3hjd
You could try using a join with sum for price > 200 group by date_sol
select m.date_sold, max(m.price)
from my_table m
inner join (
select date_sold, sum(price)
from my_table
group by date_sold
having sum(price)>200
) t on t.date_sold = m.date_sold
group by m.date_sold
You can use window functions for this:
select p.*
from (select p.*,
sum(price) over (partition by date_sold) as sum_price,
row_number() over (partition by date_sold, condition order by price desc) as seqnum
from products p
) p
where sum_price > 200 and
condition = 'used' and
seqnum = 1;
SELECT *, max(price) FROM products
where products.`condition` = 'used' and sum(products.price) > 200
GROUP BY day(date_sold)

Use CTE and UNION ALL with SQL Server 2014

My problem is that:
Create a view that shows the top 5 selling products as well as an aggregated row that shows the total sales for all other products and a Grand total row that sums all of the above.
WITH ProductTop5 AS
(
SELECT [dbo].[Product].[ProductName] AS ProductName, SUM([dbo].[SalesOrderDetail].[LineTotal]) AS TotalAmount
FROM [dbo].[Product]
JOIN [dbo].[SalesOrderDetail] ON [dbo].[Product].[ProductID] = [dbo].[SalesOrderDetail].[ProductID]
GROUP BY [dbo].[Product].[ProductName]
)
You could use ROW_NUMBER/RANK to calculate ranking of product:
WITH Product AS
(
SELECT p.[ProductName] AS ProductName,
SUM(sod.[LineTotal]) AS TotalAmount
FROM [dbo].[Product] p
JOIN [dbo].[SalesOrderDetail] sod
ON p.[ProductID] = sod.[ProductID]
GROUP BY p.[ProductName]
), ProductWithRank AS (
SELECT ProductName, Total_Amount,
ROW_NUMBER() OVER(ORDER BY Total_Amount DESC) AS rn
FROM Product
)
SELECT ProductName, TotalAmount
FROM ProductWithRank
WHERE rn <= 5
UNION ALL
SELECT 'All Others', SUM(Total_Amount)
FROM ProductWithRank
WHERE rn > 5
UNION ALL
SELECT 'Grand Total', SUM(TotalAmount)
FROM ProductWithRank;

SQL Select Group By Min() - but select other

I want to select the ID of the Table Products with the lowest Price Grouped By Product.
ID Product Price
1 123 10
2 123 11
3 234 20
4 234 21
Which by logic would look like this:
SELECT
ID,
Min(Price)
FROM
Products
GROUP BY
Product
But I don't want to select the Price itself, just the ID.
Resulting in
1
3
EDIT: The DBMSes used are Firebird and Filemaker
You didn't specify your DBMS, so this is ANSI standard SQL:
select id
from (
select id,
row_number() over (partition by product order by price) as rn
from orders
) t
where rn = 1
order by id;
If your DBMS doesn't support window functions, you can do that with joining against a derived table:
select o.id
from orders o
join (
select product,
min(price) as min_price
from orders
group by product
) t on t.product = o.product and t.min_price = o.price;
Note that this will return a slightly different result then the first solution: if the minimum price for a product occurs more then once, all those IDs will be returned. The first solution will only return one of them. If you don't want that, you need to group again in the outer query:
select min(o.id)
from orders o
join (
select product,
min(price) as min_price
from orders
group by product
) t on t.product = o.product and t.min_price = o.price
group by o.product;
SELECT ID
FROM Products as A
where price = ( select Min(Price)
from Products as B
where B.Product = A.Product )
GROUP BY id
This will show the ID, which in this case is 3.

SQL: What is appropriate query for this?

Q. List the names of the products that were not featured in a deal in last trailing 12 months.
Deals Table
i. Deal_id
ii. Product_id
iii. Deal_start_date
iv. Deal_end_date
Product Dim Table
i. Product_id
ii. Product_name
iii. Manufacturer
My answer is:
Select Product_name, Rank() over(partition by year(Deal_start_date) order by Deal_start_date desc) as Deal_date
From Product Dim Table
Right join Deals Table on Product Dim Table.Product_id=Deals Table.Product_id
where Deal_date > 1
Group by Product_name
Order by Deal_date desc
try this:
Select p.Product_name
From Product p
Where not exists
(Select * from Deals
where Product_id = p.Product_id
and Deal_start_date <= #today
and Deal_end_date >= start)
Check the followinf. /
select
Product_id, Product_name, Manufacturer
from product dim
where
product_id not in (
select product_id
from
Deals
where
deal_end_date between
Deal_end_dare>DateAdd(mm,-12, GetDate())
)

Finding the correct 'record' and using ONLY the data from that record

I have a list of products and suppliers.
I need to make sure that the Quantity is larger than zero.
If so, I need to find the product with the lowest price and list the supplier, the product (SKU), quantity and price.
My test data schema is:
create table products(merchant varchar(100), name varchar(150), quantity int, totalprice int);
insert into products values
('Supplier A', 'APC-SMT1000I', 10, 150),
('Supplier B', 'APC-SMT1000I', 15, 250),
('Supplier C', 'APC-SMT1000I', 15, 350),
('Supplier D', 'DEF-SMT1000I', 10, 500),
('Supplier E', 'DEF-SMT1000I', 35, 350),
('Supplier G', 'GHI-SMT1000I', 75, 70)
Logically, I would expect the result to read:
SUPPLIER SKU QTY PRICE
Supplier A APC-SMT1000I 10 150
Supplier D DEF-SMT1000I 35 350
Supplier G GHI-SMT1000I 75 70
My SQL Statement reads:
SELECT merchant AS Supplier, name AS sku,quantity AS Qty,
min(totalprice) AS Price FROM products where quantity > 0 group by name;
My results are:
SUPPLIER SKU QTY PRICE
Supplier A APC-SMT1000I 10 150
Supplier D DEF-SMT1000I 10 350
Supplier G GHI-SMT1000I 75 70
Obviously, the coding is finding the lowest price and displaying it, but not with the correct data.
My Question?
How can I group the data, find the record with the lowest price and make sure the programme uses ONLY the data from that record?
The easiest way to do this is using window/analytic functions. You don't specific the database you are using, but this is ANSI standard functionality available in most (but not all) databases.
Here is the syntax:
select merchant AS Supplier, name AS sku, quantity AS Qty,
totalprice AS Price
from (select p.*,
row_number() over (partition by name
order by totalprice
) as seqnum
from products p
where quantity > 0
) p
where seqnum = 1;
You could use the following query:
SELECT products.*
FROM
products INNER JOIN
(SELECT name, MIN(totalprice) min_price
FROM products
WHERE quantity>0
GROUP BY name) m
ON products.name=m.name AND products.totalprice=min_price
In the subquery I calculate the minimum total price for every name, then I'm joining this subquery with the products table, to return only the rows that have the minimum total price for that name. If there are more than one row with the minimum price, they all will be shown.
Please see fiddle here.
You haven't specified you RDBMS, so I'll provide a few queries.
This one should work in any database (but need 2 table scans):
select
p.merchant as Supplier,
p.name as sku,
p.quantity as Qty,
p.totalprice as Price
from products as p
where
p.totalprice in
(
select min(t.totalprice)
from products as t
where t.name = p.name
)
This one should work for any RDBMS which have row_number window function:
with cte as (
select *, row_number() over(partition by name order by totalprice) as rn
from products
)
select
p.merchant as Supplier,
p.name as sku,
p.quantity as Qty,
p.totalprice as Price
from cte as p
where rn = 1
This one is for PostgreSQL:
select distinct on (p.name)
p.merchant as Supplier,
p.name as sku,
p.quantity as Qty,
p.totalprice as Price
from products as p
order by p.name, p.totalprice
=> sql fiddle demo