Could not get the expected query with SQL Server - sql

I´m trying to do a SQL query but I couldn´t get the expected result. I really don´t know what is going wrong.
I have a table Product which contains (product_id, title) and other table Product_Variation which contains (product_variation_id, product_id, description, gender, price)
Basically, I have a product. For each product, have N variations.
e.g
Product: title "I have no idea"
Product_Variation: description "T-Shirt", gender "Male", price "59.90"
What I need is select Product and Product_Variation showing only the product with the lowest price.
I don´t care if a product has t-shirt, jacket or anything else as variation. I just need to get the variation which has the lowest price.
My query is:
SELECT b.product_id, b.title, MIN(b.price) as price, b.gender
FROM (
SELECT p.product_id, p.title, MIN(pv.price) AS price, pv.gender
FROM products p
join product_variation pv ON pv.product_id = p.product_id
GROUP BY p.product_id, p.title, pv.price, pv.gender
) b
GROUP BY b.product_id, b.title, b.price, b.gender
Pls, see my example in SQL Fiddle
Thanks!

Since you're using SQL 2008 you can use ROW_NUMBER to find the row with the lowest price:
SELECT *
FROM products p
INNER JOIN
(SELECT
product_id,
Description,
Gender,
Price,
ROW_NUMBER() OVER(PARTITION BY product_id ORDER BY price) Row
FROM product_variation )
pv ON pv.product_id = p.product_id
AND Row = 1
If you have two variations with the same price you'll get one random row.

-- Solution #1
SELECT *
FROM
(
SELECT p.product_id, p.title,
pv.price, pv.gender,
ROW_NUMBER() OVER(PARTITION BY p.product_id ORDER BY pv.price) AS row_num
FROM products p
join product_variation pv ON pv.product_id = p.product_id
) src
WHERE src.row_num = 1
-- Solution #2
SELECT p.product_id, p.title,
x.price, x.gender
FROM products p
cross apply
(
SELECT TOP(1) pv.price, pv.gender
FROM product_variation pv
WHERE pv.product_id = p.product_id
ORDER BY pv.price
) x

You can use the rank() window function to order stuff within a partition (group), but giving equal items the same rank:
;With b as (
Select
p.product_id,
p.title,
pv.price,
pv.gender,
rank() over(partition by p.product_id order by pv.price) rk
From
products p
Inner Join
product_variation pv
On pv.product_id = p.product_id
)
Select
b.product_id,
b.title,
b.price,
b.gender
From
b
Where
rk = 1
If you only want one per product even if there are equal products, use row_number() instead of rank()
Example Fiddle

Related

How to find the earnings from the most sold product with sql?

I have two tables:
I need to find the product name that was sold the most and the earnings from that.
The code I wrote:
SELECT *
FROM Products
WHERE ProductId = (SELECT ProductId
FROM
(SELECT
ProductId,
SUM(Quantity) AS total_order,
MAX(SUM(Quantity)) OVER () AS maxSm
FROM
Orders
GROUP BY
ProductId)
WHERE
total_order = maxSm)
But with this I just find the product name that was sold the most. Can you tell me please how can I find the earnings only from this product?
select top 1
a.name,
(b.total * a.price) as revenue
from
products a
left join (select productid, sum(quantity) as total group by productid) b
on a.productid = b.productid
order by
b.total desc
You need to join the result of your derived table to your Products table.
Without actual sample data I am unable to test, however the following should be what you need, or at least very close:
select p.Name, o.total_order, o.total_order * p.Price as TotalValue
from (
select * from (
select ProductId,
Sum(Quantity) as total_order,
Max(Sum(Quantity)) over () as maxSm
from Orders
group byProductId
)t
where total_order = maxSm
)o join Products p on p.ProductId=o.ProductId

SQL NESTED JOIN NOT USING WHERE

What is the current price of each product? Display product code, product description, unit, and its current price. Always assume that NOT ALL products HAVE unit price BUT you need to display it even if it has no unit price on it. without using WHERE script
Product Table
prodCode
description
unit
PriceHist Table
prodCode
effDate
unitPrice
This is my work... Please Help me to improve my anwswer.
SELECT p.prodCode, p.description, p.unit, MAX(ph.unitPrice) "Current Price"
FROM product p
INNER JOIN priceHist AS ph
ON p.prodCode = ph.prodCode
GROUP BY p.prodCode, p.description, p.unit
ORDER BY MAX(ph.unitPrice);
Someone said I NEED TO USE PRICEHIST TWICE
User window functions and left join:
select . . . -- whatever columns you want
from products p left join
(select ph.*,
row_number() over (partition by p.prodcode order by effdate desc) as seqnum
from pricehist ph
) ph
on ph.prodcode = p.prodcode and ph.seqnum = 1;
Try this:
SELECT a.prodCode, a.description, a.unit, SUM(b.unitPrice)
FROM ProductTable a
LEFT JOIN PriceHistTable b ON a.prodCode = b.prodCode
GROUP BY a.prodCode, a.description, a.unit, b.unitPrice
Assuming you want to select unitPrice for prodCode with latest effDate, below query should work. Explanation in comments.
select x.prodCode, x.description, x.unit, y.unitPrice
from Product x
left join (
--- Create a table y with one row per (prodCode, effDate)
--- choosing the latest effDate per prodCode
select a.prodCode, a.effDate, a.unitPrice
from PriceHist a
join (
--- Create b as (prodCode, effDate)
select prodCode, max(effDate) as maxEffDate
from PriceHist
group by prodCode
) b
on a.prodCode = b.prodCode and a.effDate = b.maxEffDate
) y
on x.prodCode = y.prodCode

Display Product Name and City where that product sold in largest quantity

I'm trying to get a query to display the product name and city where the product had the highest quantity sold. Here is the code I'm working with:
SELECT DISTINCT
(s.city),
MAX(t.quantity),
p.Name
FROM [DS715-Cameron-Erwin].dbo.Tb_Transactions AS t,
[DS715-Cameron-Erwin].dbo.Tb_Product AS p,
[DS715-Cameron-Erwin].dbo.Tb_Supplier AS s
WHERE p.prod_id = t.prod_id
AND s.Supp_ID = t.Supp_ID
GROUP BY t.Prod_ID,
p.name,
s.city
ORDER BY p.name, s.city
This is giving me the highest quantity sold for each product in each city.
Sample Data
From the screenshot there are multiple records for each product (Airplane, Auto, Boat...). I'm trying to get a single record for each product where ever the highest quantity was purchased.
So, the top record would only show for Airplane because the most orders were from there.
You want to use the ROW_NUMBER() OVER functionality to order by the quantity and then select the one with the biggest quantity over each product.
SELECT
city,
quantity,
name
FROM
(
SELECT S.city,
T.quantity,
P.name,
ROW_NUMBER() OVER
( PARTITION BY
P.name
ORDER BY t.Quantity DESC
) as RowNum
FROM
Tb_Transactions T
INNER JOIN
Tb_Product P
ON
P.prod_id = T.prod_id
INNER JOIN
Tb_Supplier S
ON
S.supp_id = T.supp_id
) a
WHERE
RowNum = 1
http://sqlfiddle.com/#!6/628458/5
For this, I would use a CTE (also I would use the explicit INNER JOIN syntax):
;With CTE
As
(
Select
s.city
, t.quantity
, p.Name
, Row_Number Over (Partition By P.Name, s.city Order By t.Quantity Desc) as RN
From [DS715-Cameron-Erwin].dbo.Tb_Transactions as t
Inner Join [DS715-Cameron-Erwin].dbo.Tb_Product as p
On p.prod_id = t.prod_id
Inner Join [DS715-Cameron-Erwin].dbo.Tb_Supplier as s
On s.Supp_ID = t.Supp_ID
)
Select
city
, quantity
, Name
From CTE
Where RN = 1

SQL nested aggregate grouping error

I'm trying to find name of product which has sold maximum units, I've two tables, purchases and products, products has pname and pid, purchases has pid, qty(units sold).
I've managed this
select p.pname, sum(q.qty) from purchases q
inner join products p on p.pid=q.pid
where p.pid=q.pid
group by p.pname
order by sum(q.qty) desc
I'm getting the result in descending order but I need only the top most selling units, multiple products can have top most selling units. When I use
max(sum(q.qty))
I get grouping error.
One approach is to derive the values first using a common table expression.
Simply put you can't wrap aggregates in other aggregates. You may be able to wrap an aggregate around an analytic however.
with cte as (select p.pname, sum(q.qty) from purchases q
inner join products p on p.pid=q.pid
where p.pid=q.pid
group by p.pname
order by sum(q.qty) desc)
Select pname, max(purchases)
from cte
group by pname
You can use ctes to do this.
1)First get the total quantity of each product
2)Then get the maximum of all those totals
3)Join it with your original query
with totals as (select pid, sum(qty) totalqty from purchases group by pid)
, t1 as (select p.pid, p.pname, sum(q.qty) totqty
from purchases q
inner join products p on p.pid=q.pid
group by p.pname)
, t2 as (select max(totalqty) maxtotal from totals)
select pname, totqty
from t1
join t2 on t1.totqty = t2.maxtotal
Analytics can simplify this for you. If you have more than one product with the same sum(qty) and that happens to be the max(sum(qty)), then this should get you them:
select pname, quantity
FROM (
select p.pname
, sum(q.qty) quantity
,rank() over (order by sum(q.qty desc) ranking
from purchases q
inner join products p on p.pid=q.pid
group by p.pname
)
where ranking = 1

SQL One result per match

I've created a query that gives prices for every product ordered by creation date.
What I now need is to only return one row per product, i.e. one price per product.
SELECT p.product_id, p.price, p.creation_date
FROM PRICE p
INNER JOIN PRODUCT pr
ON p.product_id = pr.product_id
AND p.filter_id = 3
AND (p.store_id IN (1,2,3,4) OR p.price_type = 'A')
ORDER BY p.creation_date DESC
Currently this query returns several prices per product, since several match, but I only want the newest one of those. The ORDER BY p.creation_date DESC gives the price I want as the first in the list, I want that first entry to be the only result for that product.
I've tried rownum = 1, but that only gives one result for the whole query.
Please note that this is an Oracle Database, so as far as I know TOP does not work, same goes for LIMIT.
I've treid googling it, but I can't find examples showing exactly this issue.
I forgot to mention: There are some prices which have the same creation date for the same product, so there has to be a limit of only giving the first entry for those too
Use the row_numer() windowing function to get only the latest row:
select * from (
SELECT
p.product_id,
p.price,
row_number() over (partition by product_id order by p.creation_date desc) rn,
p.creation_date
FROM PRICE p
INNER JOIN PRODUCT pr
ON p.product_id = pr.product_id
AND p.filter_id = 3
AND (p.store_id IN (1,2,3,4) OR p.price_type = 'A')
) where rn = 1
you can try this to get the price list for products
SELECT p.product_id, p.price ,first_value(p.price) over (partition by product_id
order by p.creation_date desc) new_price, p.creation_date
FROM PRICE p
INNER JOIN PRODUCT pr
ON p.product_id = pr.product_id
AND p.filter_id = 3
AND (p.store_id IN (1,2,3,4) OR p.price_type = 'A')
I don't see why you need the join on product, as... you don't use any row of product in your returned rows...
You might try :
SELECT p.product_id, MAX(p.price), p.creation_date
FROM PRICE p
INNER JOIN
(SELECT pm.product_id, MAX(pm.creation_date)
FROM PRICE pm
GROUP BY pm.product_id) most_recent_price
ON most_recent_price.product_id = p.product_id
WHERE p.filter_id = 3
AND (p.store_id IN (1,2,3,4) OR p.price_type = 'A')
GROUP BY p.product_id, p.creation_date