精彩的SQL编写者,
我试图获取某个范围内的所有日期(存储为T1中的记录),以及相关表(T2)中记录值的总和。但是,T2中的某些记录将被第三个表(T3)中的字段值过滤掉。
假设这样的表:
TABLE T1
| MonthYearKey |
|==============|
| 201401 |
| 201402 |
| 201403 |
| 201404 |
| 201405 |
| 201406 |
TABLE T2
| MonthYearKey | NextKey | MyValue |
|==============+=========+=========|
| 201402 | 6 | 10 |
| 201403 | 6 | 10 |
| 201404 | 6 | 10 |
| 201402 | 8 | 10 |
| 201403 | 8 | 10 |
| 201404 | 8 | 10 |
| 201401 | 10 | 10 |
| 201402 | 10 | 10 |
| 201406 | 10 | 10 |
TABLE T3
| NextKey | IsValid |
|=========+=========|
| 6 | 1 |
| 8 | 1 |
| 10 | 0 |
我正在运行的SQL是:
SELECT T1.MonthYearKey, SUM(ISNULL(T2.MyValue, 0)) AS SumOfValues
FROM T1
LEFT OUTER JOIN T2 ON T1.MonthYearKey = T2.MonthYearKey
LEFT OUTER JOIN T3 ON T2.NextKey = T3.NextKey
WHERE ISNULL(T3.IsValid, 1) = 1
GROUP BY T1.MonthYearKey
我预期的输出是:
| MonthYearKey | SumOfValues |
|==============+=============|
| 201401 | 0 |
| 201402 | 20 |
| 201403 | 20 |
| 201404 | 20 |
| 201405 | 0 |
| 201406 | 0 |
但是,正如您在SQL Fiddle中看到的那样,201401和201406个月完全退出了结果。我假设这是因为它选择了NextKey = 10的记录,然后由IsValid = 0过滤掉。
问题:如何获取所有MonthYearKeys,即使是那些当前在我的SQL中被过滤掉的那些?
答案 0 :(得分:4)
在where
子句中应用过滤器时,会丢失行 - 包括用于group by
的列。
相反,使用条件聚合:
SELECT T1.MonthYearKey,
COALESCE(SUM(case when t3.isvalid is null or t3.isvalid = 1
then T2.MyValue
end), 0
) as SumOfValues
FROM T1 LEFT OUTER JOIN
T2
ON T1.MonthYearKey = T2.MonthYearKey LEFT OUTER JOIN T3
ON T2.NextKey = T3.NextKey
GROUP BY T1.MonthYearKey;
答案 1 :(得分:2)
试试这个:
SELECT T1.MonthYearKey, SUM(ISNULL(T2.MyValue, 0)) AS SumOfValues
FROM T1
LEFT OUTER JOIN (
SELECT T2.MyValue, T2.MonthYearKey
FROM T2
JOIN T3 ON T2.NextKey = T3.NextKey AND ISNULL(T3.IsValid, 1) = 1
) T2 ON T1.MonthYearKey = T2.MonthYearKey
GROUP BY T1.MonthYearKey
在此尝试:http://www.sqlfiddle.com/#!3/4a333/26
修改强>:
没有嵌套查询:
SELECT T1.MonthYearKey, SUM(ISNULL(T2.MyValue, 0)) AS SumOfValues
FROM T2
JOIN T3 ON T2.NextKey = T3.NextKey AND T3.IsValid = 1
RIGHT OUTER JOIN T1 ON T1.MonthYearKey = T2.MonthYearKey
GROUP BY T1.MonthYearKey
通过更改JOIN
优先级
SELECT T1.MonthYearKey, SUM(ISNULL(T2.MyValue, 0)) AS SumOfValues
FROM T1
LEFT OUTER JOIN (T2 JOIN T3 ON T2.NextKey = T3.NextKey AND T3.IsValid = 1)
ON T1.MonthYearKey = T2.MonthYearKey
GROUP BY T1.MonthYearKey
SQL Fidle:http://www.sqlfiddle.com/#!3/4a333/45