Reputation: 1580
I have a SQL Query that returns the to 27 selling products from the database:
SELECT TOP 27 ROW_NUMBER() OVER (ORDER BY ttP.ProductName ASC) AS Rno, ttP.*, ttI.ImageID FROM tblProducts AS ttP
LEFT OUTER JOIN (SELECT ImageID, ProductID FROM tblImages WHERE Main = 1) AS ttI ON ttP.ProductID = ttI.ProductID
LEFT OUTER JOIN (SELECT TOP 27 ProductID, SUM(Quantity) AS NumSold FROM tblOrderItems GROUP BY ProductID ORDER BY SUM(Quantity) DESC)
AS ttOI ON ttP.ProductID = ttOI.ProductID
WHERE ttP.ProductVisibleOnline = 1 AND ttP.CollectionID IS NULL
AND ttOI.NumSold IS NOT NULL
ORDER BY ttOI.NumSold DESC, ttP.ProductName ASC
I want to add the following WHERE clause so it returns the top 27 products that have a certain feature
WHERE ttP.ProductID IN (SELECT ProductID FROM tblProductsFeatures WHERE FeatureID = 3)
So I go ahead and add it toward the end of the statement and end up with this:
SELECT TOP 27 ROW_NUMBER() OVER (ORDER BY ttP.ProductName ASC) AS Rno, ttP.*, ttI.ImageID FROM tblProducts AS ttP
LEFT OUTER JOIN (SELECT ImageID, ProductID FROM tblImages WHERE Main = 1) AS ttI ON ttP.ProductID = ttI.ProductID
LEFT OUTER JOIN (SELECT TOP 27 ProductID, SUM(Quantity) AS NumSold FROM tblOrderItems GROUP BY ProductID ORDER BY SUM(Quantity) DESC)
AS ttOI ON ttP.ProductID = ttOI.ProductID
WHERE ttP.ProductVisibleOnline = 1 AND ttP.CollectionID IS NULL
AND ttOI.NumSold IS NOT NULL
AND ttP.ProductID IN (SELECT ProductID FROM tblProductsFeatures WHERE FeatureID = 3)
ORDER BY ttOI.NumSold DESC, ttP.ProductName ASC
This returns 11 records which are a subset of the top 27 selling products without the where clause. I'm not understanding where I can put the where clause so that I get the top 27 selling products with FeatureID = 3. Any help would be greatly appreciated.
Upvotes: 0
Views: 239
Reputation: 62861
Looking at how you're joining on the tblOrderItems
table, perhaps this is what you're looking for instead:
SELECT TOP 27 ROW_NUMBER() OVER (ORDER BY ttP.ProductName ASC) AS Rno,
ttP.*, ttI.ImageID
FROM tblProducts AS ttP
LEFT OUTER JOIN (
SELECT ImageID, ProductID
FROM tblImages
WHERE Main = 1) AS ttI ON ttP.ProductID = ttI.ProductID
INNER JOIN (
SELECT TOP 27 ProductID, SUM(Quantity) AS NumSold
FROM tblOrderItems
WHERE ProductID IN (SELECT ProductID
FROM tblProductsFeatures
WHERE FeatureID = 3)
GROUP BY ProductID
ORDER BY SUM(Quantity) DESC) AS ttOI ON ttP.ProductID = ttOI.ProductID
WHERE ttP.ProductVisibleOnline = 1
AND ttP.CollectionID IS NULL
ORDER BY ttOI.NumSold DESC,
ttP.ProductName ASC
This also replaces one of your outer joins
with an inner join
and removes some of the where
criteria.
Upvotes: 1
Reputation: 107387
The problem here is that you are finding the top 27 products in a derived table (SELECT TOP 27 ...AS ttOI
), but then applying further filters in the outer select. This has the effect of further reducing your product row count from 27, down to 11, since the rows eliminated by the outer filter will not somehow force the inner 27 restriction to be reevaluated against the new criteria.
I would suggest that you do ALL filtering against the eligible products before joining other tables, and ranking the product popularity. Note also that if a product has more than one image, you could have the product duplicated?
SELECT ROW_NUMBER() OVER (ORDER BY ttP.ProductName ASC) AS Rno,
ttP.*, ttI.ImageID
FROM
tblProducts AS ttP
INNER JOIN
(
SELECT TOP 27 ttp.ProductId, SUM(ttOI.Quantity) AS NumSold
FROM tblProducts AS ttP
INNER JOIN tblOrderItems ttOI
ON ttP.ProductID = ttOI.ProductID
INNER JOIN tblProductsFeatures tPF
ON ttP.ProductID = tPF.ProductID
WHERE ttP.ProductVisibleOnline = 1
AND ttP.CollectionID IS NULL
AND ttOI.NumSold IS NOT NULL
AND tPF.FeatureID = 3
GROUP BY ttp.ProductID
ORDER BY SUM(Quantity) DESC) AS ep -- Eligible products
ON ttP.ProductID = ep.ProductID
LEFT OUTER JOIN -- Duplicate Rows if there is more than one image here
tblImages AS ttI
ON ttP.ProductID = ttI.ProductID
AND ttI.Main = 1
ORDER BY ep.NumSold DESC, ttP.ProductName ASC;
Upvotes: 0