将OUTER JOIN与WHERE条件一起使用

时间:2017-08-16 14:09:37

标签: sql sql-server

我有两个相关的表格如下:

CREATE TABLE Vehicle (
  Id INT NOT NULL PRIMARY KEY,
  Name VARCHAR(255) NOT NULL
);
INSERT INTO Vehicle (Id, Name) VALUES (1, 'Car');
INSERT INTO Vehicle (Id, Name) VALUES (2, 'Van');
INSERT INTO Vehicle (Id, Name) VALUES (3, 'Motorcycle');

CREATE TABLE Signal (
  Id INT NOT NULL PRIMARY KEY,
  VehicleId INT NOT NULL,
  Reading INT,
  StartTime DATE
);
INSERT INTO Signal (Id, VehicleId, Reading, StartTime) VALUES (1, 1, 10, '2016-12-10');
INSERT INTO Signal (Id, VehicleId, Reading, StartTime) VALUES (2, 1, 15, '2017-01-10');
INSERT INTO Signal (Id, VehicleId, Reading, StartTime) VALUES (3, 1, 4, '2017-02-10');
INSERT INTO Signal (Id, VehicleId, Reading, StartTime) VALUES (4, 2, 4, '2017-03-10');

当我执行这样的OUTER JOIN时,它的行为符合预期:

SELECT v.Name, SUM(s.Reading)
FROM Signal s
RIGHT OUTER JOIN Vehicle v ON v.Id = s.VehicleId
GROUP BY v.Name

(actual and expected result):
Car | 29
Motorcycle | NULL
Van | 4

但是当我添加这样的WHERE条件时,它不再符合我的期望:

SELECT v.Name, SUM(s.Reading)
FROM Signal s
RIGHT OUTER JOIN Vehicle v ON v.Id = s.VehicleId
WHERE StartTime > '2017-01-01'
GROUP BY v.Name

(actual result):
Car | 19
Van | 4

(expected result):
Car | 19
Motorcycle | NULL
Van | 4

为什么在添加WHERE条件时没有得到预期的结果,我该如何解决?

3 个答案:

答案 0 :(得分:0)

因为WHERE StartTime > '2017-01-01'使您的外部联接成为一个联接并删除所有不在表格信号中的条目。

将where条件移动到on子句:

SELECT v.Name, SUM(s.Reading)
FROM Signal s
RIGHT OUTER JOIN Vehicle v ON v.Id = s.VehicleId AND StartTime > '2017-01-01'
GROUP BY v.Name

顺便说一句:列名StartTime有点令人困惑,因为看起来你有日期和时间部分。更好的名字是StartDate

答案 1 :(得分:0)

WHERE条件移至ON子句:

SELECT v.Name, SUM(s.Reading)
FROM Signal s
RIGHT OUTER JOIN Vehicle v
    ON v.Id = s.VehicleId AND
       StartTime > '2017-01-01'
GROUP BY v.Name

但通常LEFT JOIN似乎更为普遍,因此您可以将此查询重写为:

SELECT
    v.Name,
    SUM(s.Reading) AS reading_sum
FROM Vehicle v
LEFT JOIN Signal s
    ON v.Id = s.VehicleId AND
       s.StartTime > '2017-01-01'
GROUP BY v.Name

答案 2 :(得分:0)

您正在使用右外连接,因此它将获取Vehicle表,然后连接到Signal表中的任何匹配记录。 where子句是对Signal表进行过滤,因此如果Signal表中没有匹配记录供Vehicle表连接,则它将为NULL,然后使用where并删除该结果。

也许您想要的是将“StartTime>'2017-01-01'”放入ON cluse中?或者您可能正在寻找左外连接而不是右连接。很难说不知道你的意图