why won't this query work properly?
-
23-12-2019 - |
Question
my MasterSales
table looks like this
SalesDate | Category | Total
-----------------------------
1/1/2000 01 100
1/1/2000 02 110
1/2/2000 01 80
1/2/2000 03 20
and my Category
table looks like this
ID | Name ---------- 01 | A 02 | B 03 | C 04 | D
my query looks like this:
SELECT m.SalesDate, c.Name, SUM(ISNULL(m.Total,0)) AS TotalSales
FROM MasterSales m
LEFT JOIN Category c ON c.ID = m.Category
WHERE m.SalesDate BETWEEN '1/1/2000' AND '1/2/2000'
the result I want is like this:
SalesDate | Name | TotalSales
------------------------------
1/1/2000 A 100
1/1/2000 B 110
1/1/2000 C 0
1/1/2000 D 0
1/2/2000 A 80
1/2/2000 B 0
1/2/2000 C 20
1/2/2000 D 0
but the result I get looks this:
SalesDate | Name | TotalSales
------------------------------
1/1/2000 A 100
1/1/2000 B 110
1/2/2000 A 80
1/2/2000 C 20
I already tried using RIGHT JOIN
instead of LEFT JOIN
and switching the table on FROM
clause but the result is still the same. can anyone help explain to me why it won't work properly?
P.S. : I'm using SQL Server 2005 (if it matters)
Solution
and here is my answer
WITH MasterSales (SalesDate, Category, Total) AS (
SELECT '1/1/2000','01',100
UNION SELECT '1/1/2000','02',110
UNION SELECT '1/2/2000','01',80
UNION SELECT '1/2/2000','03',20
), Category (ID, Name) AS (
SELECT '01','A'
UNION SELECT '02','B'
UNION SELECT '03','C'
UNION SELECT '04','D'
), getDates AS (
SELECT DISTINCT SalesDate
FROM MasterSales
WHERE SalesDate BETWEEN '1/1/2000' AND '1/2/2000'
)
SELECT gD.SalesDate, C.Name, SUM(ISNULL(MS.Total,0)) AS TotalSales
FROM getDates AS gD
CROSS JOIN Category AS C
LEFT JOIN MasterSales AS MS
ON MS.Category = C.ID
AND MS.SalesDate = gD.SalesDate
GROUP BY gD.SalesDate, C.Name
OTHER TIPS
Try this. This covers all dates where you have MasterSales. In other words, this fills in the missing categories for the day. However, you're looking to fill in missing dates as well, you'll need to create a date control table.. look into recursive cte for the date table.
;with control_table as (
select distinct SalesDate, ID
from MasterSales ms
cross join Category c
where ms.SalesDate between '1/1/2000' AND '1/2/2000'
)
select ct.SalesDate, c.Name as Category, coalesce(sum(ms.Total),0) as Total
from control_table ct
inner join Category c
on ct.ID = c.ID
left join MasterSales ms
on ct.SalesDate = ms.SalesDate
and ct.ID = ms.Category
group by ct.SalesDate, c.Name
order by ct.SalesDate asc, c.Name asc
Finally, your problem is solved. Use this query:
SELECT AAA.SalesDate,AAA.Name,ISNULL(BBB.TotalSales,0) as TotalSales
FROM (
(SELECT m.SalesDate, c.Name
FROM MasterSales m,Category c
WHERE m.SalesDate BETWEEN '1/1/2000' AND '1/2/2000'
GROUP BY m.SalesDate,c.Name) AAA
LEFT JOIN
(SELECT m.SalesDate,c.Name, SUM(ISNULL(m.Total,0)) AS TotalSales
FROM MasterSales m,Category c
WHERE m.SalesDate BETWEEN '1/1/2000' AND '1/2/2000'
AND c.ID=m.Category
GROUP BY m.SalesDate,c.Name) BBB
on AAA.SalesDate=BBB.SalesDate AND AAA.Name=BBB.Name)
Explanation:
The first part of the query (AAA) selects all combination of SalesDate
and Category
.
The second part of the query (BBB) selects SalesDate
,Category
and TotalSales
.
And then we join both of them (AAA & BBB) on SalesDate
and Category
.
Works perfectly !!!. See SQL Fiddle.
UPDATED: changed the method of creating temp table using sam yi
logic
I suggest you create an addition table.
;WITH control_table AS (
SELECT DISTINCT SalesDate, Name
FROM MasterSales ms
CROSS JOIN Category c
)
SELECT d.SalesDate,
c.name,
COALESCE(sum(m.total),0) totalsales
FROM control_table d
LEFT OUTER JOIN Category c
ON d.Name = c.name
LEFT OUTER JOIN MasterSales m
ON (c.id = m.category
AND d.SalesDate = m.salesdate)
WHERE d.SalesDate BETWEEN '1/1/2000'
AND '1/2/2000'
GROUP BY
d.SalesDate,
c.name
ORDER BY
d.SalesDate,
c.name;
SELECT cj.Date, cj.Name, IsNull(m.Total,0) Total
FROM (SELECT d.Date, c.Name, c.Id
FROM (SELECT DISTINCT SalesDate Date
FROM MasterSales) d, Category c) cj
LEFT JOIN MasterSales m ON m.SalesDate = cj.Date
AND cj.Id = m.Category
http://www.sqlfiddle.com/#!3/d1344/3
Add your date-between conditions
And I'm sure there ate better ways to do this.
Cheers