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#.
Advertisement
Answer
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