17

我有一个多表连接(示例中只显示了两个),我需要保留基表中的所有行。显然,我使用 LEFT JOIN 来包含基表上的所有行。如果没有 WHERE 子句,它工作得很好——当右表中不存在行时,左表中的行仍然显示,右表中的列中只有一个 0。数据集中的前两行是左表中的标签和右表中的行数,按标签分组。当标签没有分配 Table2 中的值时,我想要的只是计数为 0。

表格1

Label | FK
----------
Blue  | 1
Red   | 2
Green | 3

表2

Values | pk    | Date
---------------------------
Dog    | 1     | 02/02/2010
Cat    | 2     | 02/02/2010
Dog    | 1     | 02/02/2010
Cat    | 2     | 02/02/2010

查询

SELECT 1.Label, COUNT(2.values)
FROM Table1 1
    LEFT JOIN Table2 2 ON 1.fk = 2.pk
GROUP BY 1.Label

良好的结果集 - 无过滤器

Blue  | 2
Red   | 2
Green | 0

伟大的!

我的问题是,当我添加过滤条件以从右表中删除行时,为我的左连接行删除了行(将它们归零),左行被删除。即使它们的计数被过滤为零,我也需要保留左行。

SELECT 1.Label, COUNT(2.values)
FROM Table1 1
    LEFT JOIN Table2 2 ON 1.fk = 1.pk
WHERE 2.Date BETWEEN '1/1/2010' AND '12/31/2010'    
GROUP BY 1.Label

Bummer 结果集 - 过滤器之后

Blue | 2
Red  | 2

公爵们!

那么,到底是什么?我是否需要使用过滤后的数据集获取临时表,然后将其加入左表?我错过了什么?谢谢!

进行第二次联接或递归联接。获取我的“好”连接表,获取第二个“过滤”表,然后左连接它们

4

4 回答 4

28

您正在筛选中的第二个表where。这些值可能是NULL比较NULL失败。

where条件移至on子句:

SELECT 1.Label, COUNT(2.values)
FROM Table1 1 LEFT JOIN
     Table2 2
     ON 1.fk = 1.pk AND
        2.Date BETWEEN 1/1/2010 AND 12/31/2010    
GROUP BY 1.Label

笔记:

日期格式保留问题中的日期。但是,我不提倡使用BETWEEN日期,并且条件应使用标准日期格式:

SELECT 1.Label, COUNT(2.values)
FROM Table1 1 LEFT JOIN
     Table2 2
     ON 1.fk = 1.pk AND
        2.Date >= '2010-01-01' AND
        2.Date < '2011-01-01'
GROUP BY 1.Label;

一些数据库支持 SQL Standard 关键字DATE来识别日期常量。

于 2013-09-11T20:23:18.073 回答
4

只需将子句中的条件移至WHERE子句即可ON

LEFT JOIN Table2 2 ON 1.fk = 1.pk AND 2.Date BETWEEN '1/1/2010' AND '12/31/2010'
于 2013-09-11T20:23:43.767 回答
1

首先,我认为将数字作为别名并不是一个好主意。请改用字符或单词。

我会将标准放在联接中。

SELECT T1.Label, COUNT(T2.values)
FROM Table1 T1
    LEFT JOIN Table2 T2 ON T1.fk = T1.pk
    AND T2.Date BETWEEN '20100101' AND '20101231'    
GROUP BY T1.Label

其他的建议:

  1. 我会使用 ANSI(yyyyMMdd) 格式的日期,所以没有误解。
  2. 我会知道 BETWEEN 因为不清楚如果日期是“20101231 01:00”你想做什么你想包括那个日期吗?>= 和 <= 或 >= 和 < 更清晰。
于 2013-09-11T20:23:16.337 回答
0

如果您使用的是 SQL Server,请在日期两边加上单引号。如果不是,那么它将评估表达式而不是日期。

BETWEEN '1/1/2010' AND '12/31/2010'
于 2013-09-11T20:24:24.733 回答