Reputation: 9485
I have a table of product variants, grouped by a product key. I also have a category table which is joined off the ProductKey
. So if I query for products in a category or many categories I will get a list variants that match the joined ProductKeys
.
SELECT Pk, ProductKey, Name, Description, Price
FROM ProductVariant
INNER JOIN Product2Category ON ProductVariant.ProductKey = Product2Category.ProductKey
INNER JOIN Category ON Product2Category.CategoryKey = Category.pk WHERE Category.pk IN(@categorykeys)
Which would result in example data like this
Pk, ProductKey, Name, Description, Price
20, 1, 'Product One - Variant One', 'Description', 25.65
21, 1, 'Product One - Variant Two', 'Description', 24.65
22, 1, 'Product One - Variant Three', 'Description', 29.65
23, 2, 'Product Two - Variant', 'Description', 26.65
24, 2, 'Product Two - Variant', 'Description', 23.65
25, 2, 'Product Two - Variant', 'Description', 25.65
The issue is I just want to return a single product per ProductKey
. Either the cheapest of the group. So the results would be
Pk, ProductKey, Name, Description, Price
21, 1, 'Product One - Variant Two', 'Description', 24.65
24, 2, 'Product Two - Variant', 'Description', 23.65
Or the most expensive. So the results would be
Pk, ProductKey, Name, Description, Price
22, 1, 'Product One - Variant Three', 'Description', 29.65
23, 2, 'Product Two - Variant', 'Description', 26.65
How can I do this efficiently within the SELECT sql query? Currently I'm returning all and doing the filtering in memory on the server in C#.
Upvotes: 2
Views: 196
Reputation: 66
Perhaps you can also try using the cross apply operator like :
SELECT c2.Pk, v.ProductVariant, c2.Price
FROM ProductVariant as v CROSS APPLY
(SELECT TOP(1) Price, Pk
from Product2Category as c2
where v.ProductVariant = c.ProductVariant order by price desc
) as o inner join
Category as c
on c2.CategoryKey = c.CategoryKey -- this will return the highest price for each product, inverse the order by inside the cross apply and will therefore return the lowest.
I am not familiar with the structure of your tables but the logic is there as the cross apply method as inline is quite fast.
Upvotes: 3
Reputation: 29993
If I understand you correctly, you need to use ROW_NUMBER()
to get the expected results:
Table:
CREATE TABLE Data (
Pk int,
ProductKey int,
Name varchar(100),
Description varchar(50),
Price numeric(10, 2)
)
INSERT INTO Data
(Pk, ProductKey, Name, Description, Price)
VALUES
(20, 1, 'Product One - Variant One', 'Description', 25.65),
(21, 1, 'Product One - Variant Two', 'Description', 24.65),
(22, 1, 'Product One - Variant Three', 'Description', 29.65),
(23, 2, 'Product Two - Variant', 'Description', 26.65),
(24, 2, 'Product Two - Variant', 'Description', 23.65),
(25, 2, 'Product Two - Variant', 'Description', 25.65)
Statement for the cheapest product:
SELECT
t.Pk, t.ProductKey, t.Name, t.Description, t.Price
FROM (
SELECT
Pk, ProductKey, Name, Description, Price,
ROW_NUMBER() OVER (PARTITION BY ProductKey ORDER BY Price ASC) AS Rn
FROM Data
) t
WHERE t.Rn = 1
Statement for the most expensive product:
SELECT
t.Pk, t.ProductKey, t.Name, t.Description, t.Price
FROM (
SELECT
Pk, ProductKey, Name, Description, Price,
ROW_NUMBER() OVER (PARTITION BY ProductKey ORDER BY Price DESC) AS Rn
FROM Data
) t
WHERE t.Rn = 1
Results:
-------------------------------------------------------------
Pk ProductKey Name Description Price
-------------------------------------------------------------
21 1 Product One - Variant Two Description 24.65
24 2 Product Two - Variant Description 23.65
-------------------------------------------------------------
Pk ProductKey Name Description Price
-------------------------------------------------------------
22 1 Product One - Variant Three Description 29.65
23 2 Product Two - Variant Description 26.65
Upvotes: 3
Reputation: 16908
You can try this below logic. Remember, this is not the exact query, just sample query where from you can take necessary logical help.
SELECT * FROM your_table A
INNER JOIN
(
SELECT ProductKey,MIN(Price) min_price,MAX(Price) max_price
FROM your_table
GROUP BY ProductKey
)B ON A.ProductKey = B.ProductKey
AND(
A.Price = B.Min_Price
OR
A.Price = B.max_price
)
Upvotes: 2