SQL: What is appropriate query for this? - sql

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

Related

SQL Query - second ID of a list ordered by date and ID

I have a SQL database with a list of Customer IDs CustomerID and invoices, the specific product purchased in each invoice ProductID, the Date and the Income of each invoice . I need to write a query that will retrieve for each product, which was the second customer who made a purchase
How do I do that?
EDIT:
I have come up with the following query:
SELECT *,
LEAD(CustomerID) OVER (ORDER BY ProductID, Date) AS 'Second Customer Who Made A Purchase'
FROM a
ORDER BY ProductID, Date ASC
However, this query presents multiple results for products that have more than two purchases. Can you advise?
SELECT a2.ProductID,
(
SELECT a1.CustomerID
FROM a a1
WHERE a1.ProductID = a2.ProductID
ORDER BY Date asc
LIMIT 1,1
) as SecondCustomer
FROM a a2
GROUP BY a2.ProductID
I need to write a query that will retrieve for each product, which was the second customer who made a purchase
This sounds like a window function:
select a.*
from (select a.*,
row_number() over (partition by productid order by date asc) as seqnum
from a
) a
where seqnum = 2;

Select top 10 products sold in each year

I have two tables :
Sales
columns: (Sales_id, Date , Customer_id, Product_id, Purchase_amount):
Product
columns: ( Product_id, Product_Name, Brand_id,Brand_name)
I have to write a query to find the top 10 products sold every year. The query I have right now is :
WITH PH AS
(SELECT P.Product_Name, LEFT(S.Date,4) "SYEAR", COUNT(S.Product_id) "Product Count"
FROM Sales S LEFT JOIN Product P
ON S.Product_Id=P.Product_Id
GROUP BY P.Product_Name, LEFT(S.Date,4)
SELECT P.Product_Name, "SYEAR", "Product_Count"
FROM (SELECT P.Product_Name, "SYEAR", "Product_Count",
RANK OVER (PARTITION BY "SYEAR" ORDER BY "Product_Count" DESC) "TEMP"
)
WHERE "TEMP"<=10
This doesn't seem like the most optimized query. Can you please help me with that? Can there be an alternate version to obtain the required result?
Notes
The main reason for the repetition of the code is to enable grouping by the year. There's no field for the year in the given table.
The date format is: YYYYMMDD (example: 20200630)
Any help will be appreciated. Thanks in advance
You can combine the window functions with the aggregation:
SELECT PY.*
FROM (SELECT P.Product_Name, LEFT(S.Date,4) AS YEAR, COUNT(*) AS CNT,
RANK() OVER (PARTITION BY LEFT(S.Date, 4) ORDER BY COUNT(*) DESC) AS SEQNUM
FROM Sales S LEFT JOIN
Product P
ON S.Product_Id = P.Product_Id
GROUP BY P.Product_Name, LEFT(S.Date, 4)
) PY
WHERE SEQNUM <= 10;
From a performance perspective, this probably generates an execution plan very similar to your query. It is however simpler to follow.

Select multiple columns with not all columns mentioned in Groupby - Postgres v12

I have a table which contain review_id,product_id,ratings,reviewer_id,review_comments. The table i have is as below.
My need is quite simple but I have issues figuring it out. Need is to get product_id, rating, reviewer_id and review_comments of the product_id which has the max value of review_id
With below query, I am able to get product_id and review_id properly.
SELECT product_id,max(review_id) as review_id
FROM public.products Group by product_id;
But when I try to add ratings, reviewer_id, and review_comments, it raises an error that those columns have to be part of a groupby and if I add those columns, grouping gets disturbed since I need grouping only on product_id and nothing else.
Is there a way to solve this?
My expected result should contain all row content with review_id 7,5,8 since for product_id 1 review_id 7 is highest and for product_id 2 review_id 5 is highest and for product_id 3 review_id 8 is highest.
Try PostgreSQL's DISTINCT ON:
SELECT DISTINCT ON (product_id)
product_id,
review_id,
rating,
reviewer_id,
review_comments
FROM products
ORDER BY product_id, review_id DESC;
This will return the first row for each product_id in the ORDER BY order.
This can be done with NOT EXISTS:
select p.product_id, p.rating, p.reviewer_id, p.review_comments
from public.products p
where not exists (
select 1 from public.products
where product_id = p.product_id and review_id > p.review_id
)
You can try below way-
select * from tablename a
where review_id =(select max(review_id) from tablename b where a.product_id=b.product_id)
or use row_number()
select * from
(
select *, row_number() over(partition by product_id order by review_id desc) as rn
from tablename
)A where rn=1

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 query for table with multiple keys?

I am sorry if this seems too easy but I was asked this question and I couldn't answer even after preparing SQL thoroughly :(. Can someone answer this?
There's a table - Seller id, product id, warehouse id, quantity of products at each warehouse for each product as per each seller.
We have to list the Product Ids with Seller Id who has highest number of products for that product and the total number of units he has for that product.
I think I got confused because there were 3 keys in the table.
It's not quite clear which DBMS you are using currently. The below should work if your DBMS support window functions.
You can find count of rows for each product and seller, rank each seller within each product using window function rank and then use filter to get only top ranked sellers in each product along with count of units.
select
product_id,
seller_id,
no_of_products
from (
select
product_id,
seller_id,
count(*) no_of_products,
rank() over (partition by product_id order by count(*) desc) rnk
from your_table
group by
product_id,
seller_id
) t where rnk = 1;
If window functions are not supported, you can use correlated query to achieve the same effect:
select
product_id,
seller_id,
count(*) no_of_products
from your_table a
group by
product_id,
seller_id
having count(*) = (
select max(cnt)
from (
select count(*) cnt
from your_table b
where b.product_id = a.product_id
group by seller_id
) t
);
Don't know why having id columns would mess you up... group by the right columns, sum up the totals and just return the first row:
select *
from (
select sellerid, productid, sum(quantity) as total_sold
from theres_a_table
group by sellerid, productid
) x
order by total_sold desc
fetch first 1 row only
If I do not think about optimization, straight forward answer is like this
select *
from
(
select seller_id, product_id, sum(product_qty) as seller_prod_qty
from your_table
group by seller_id, product_id
) spqo
inner join
(
select product_id, max(seller_prod_qty) as max_prod_qty
from
(
select seller_id, product_id, sum(product_qty) as seller_prod_qty
from your_table
group by seller_id, product_id
) spqi
group by product_id
) pmaxq
on spqo.product_id = pmaxq.product_id
and spqo.seller_prod_qty = pmaxq.max_prod_qty
both spqi (inner) and sqpo (outer) give you seller, product, sum of quantity across warehouses. pmaxq gives you max of each product again across warehouses, and then final inner join picks up sum of quantities if seller has highest (max) of the product (could be multiple sellers with the same quantity). I think this is the answer you are looking for. However, I'm sure query can be improved, since what I'm posting is the "conceptual" one :)