Reputation: 1423
I have a database that keeps track of retail sales based on Location. I have a location table with an ID and various other location specific information, a retail sale item table with an itemID and all other item information, and a retail sale usage table that has a combination of location and item ID's as well as other information about the sale(quantity, sale price, etc). I am trying to make a query that will return all retail sale items and the sum of the quantity sold for each for a given date range grouped by location.
I found this SO question and mimicked Tony Andrews' answer to a point but it isn't acting as I would expect.
I can get a complete list of items(all 29 items are retuned as expected) and quantities sold if I do not include the date range:
SELECT i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, AVG(u.Price) AS Price, SUM(u.Quantity) AS Quantity, l.Description, l.LocationID, i.Description AS ItemDescription
FROM Location as l CROSS JOIN RetailSaleItems as i
INNER JOIN RetailSaleUsage as u ON l.LocationID = i.LocationID AND i.ItemNo = u.ItemNo
WHERE (l.LocationID IN(1)) AND (i.Inactive = 0)
GROUP BY i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, l.[Description], l.LocationID, i.[Description]
ORDER BY l.[Description]
As soon as I try to limit the date range, say to January of this year, I lose 5 records and as best I can tell its because they don't show in the RetailSaleusage table within the date range specified. But that doesn't make sense because there are 15 other items that don't show up in that date range either but they appear in the results.
The SQL I am using with the date range is:
SELECT i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, AVG(u.Price) AS Price, SUM(u.Quantity) AS Quantity, l.Description, l.LocationID, i.Description AS ItemDescription
FROM Location as l CROSS JOIN RetailSaleItems as i
INNER JOIN RetailSaleUsage as u ON l.LocationID = i.LocationID AND i.ItemNo = u.ItemNo
WHERE (l.LocationID IN(1))
AND (i.Inactive = 0) AND (u.[Date] >= '1/1/2013' AND u.[Date] <= '1/31/2013')
GROUP BY i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, l.[Description], l.LocationID, i.[Description]
ORDER BY l.[Description]
I found this article on MSDN that talks about Cross joins acting like inner joins when they include a where
clause but one of the comments states that that only applies when the where
dictates the join criteria. Since the where
of my SQL is just limiting the date range I'm assuming that's not the issue.
Any direction on this would be very appreciated.
Upvotes: 0
Views: 131
Reputation: 4234
You probably don't need a CROSS JOIN
. They aren't used all that much in practice (rarely, they're very useful, but rarely).
Anyway, you may want to do some research into [LEFT|RIGHT] [OUTER] JOIN
s (the OUTER
keyword is optional). With INNER JOIN
s, records must exist in each table that is joined. With OUTER JOIN
s, a record must exist in at least one table in order for data to be returned. Which table is determined by whether you're performing a LEFT JOIN
or a RIGHT JOIN
.
I've taken a stab at writing the correct query below--but I don't know your data model and made some "intuitive guesses". Play with that and see what you can come up with.
SELECT i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, AVG(u.Price) AS Price, SUM(u.Quantity) AS Quantity, l.Description, l.LocationID, i.Description AS ItemDescription
FROM Location as l
INNER JOIN RetailSaleItems as i ON i.LocationID = l.LocationID
LEFT JOIN RetailSaleUsage as u ON l.LocationID = u.LocationID
WHERE (l.LocationID IN(1)) AND (i.Inactive = 0) AND (i.ItemNo = u.ItemNo OR u.ItemNo IS NULL)
GROUP BY i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, l.[Description], l.LocationID, i.[Description]
ORDER BY l.[Description]
UPDATE: To help you answer your question per your comment below, you need to change where you're restricting by date range. Currently, you're restricting all results by the specified date range in the RetailSaleUsage
table because the condition is placed in the WHERE
clause. Instead, we need to specify the restriction as a condition of JOIN
on the join to the RetailSaleUsage
table. Have a look at the query below. That should do it for you.
SELECT i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, AVG(u.Price) AS Price, SUM(u.Quantity) AS Quantity, l.Description, l.LocationID, i.Description AS ItemDescription
FROM Location as l
INNER JOIN RetailSaleItems as i ON i.LocationID = l.LocationID
LEFT JOIN RetailSaleUsage as u ON l.LocationID = u.LocationID AND u.[Date] BETWEEN '1/1/2013' AND '1/31/2013'
WHERE (l.LocationID IN(1)) AND (i.Inactive = 0) AND (i.ItemNo = u.ItemNo OR u.ItemNo IS NULL)
GROUP BY i.WholesaleCost, i.RetailPrice, i.OnHandQuan, u.ItemNo, l.[Description], l.LocationID, i.[Description]
ORDER BY l.[Description]
HTH.
Upvotes: 2