如何在连接中使用 where 子句
How to use a where clause with a join
Table Student
Id
Name
1
Name
2
Name
Table Classes
Id
Name
Number
1
class1
2
2
class1
3
和一个连接 table
StudentId
ClassId
Income
1
1
5
2
2
6
和查询
select sum(scr.Income)
from Student s
left join StudentClassRelation scr on scr.classId = s.Id
left join Class c on c.Id = scr.classId and c.Number > 4
我想将 c.Number > 4
移动到第二行,以便仅接收来自 类 且数字大于 4 的收入。我无法显着更改查询,因为它是更大的。我需要以某种方式过滤 StudentClassRelation
CREATE TABLE Student
(
Id INT PRIMARY KEY,
Name VARCHAR(100),
);
CREATE TABLE Class
(
Id INT PRIMARY KEY,
Name VARCHAR(100),
Number int
);
CREATE TABLE StudentClassRelation
(
Income int,
StudentID INT NOT NULL,
ClassID INT NOT NULL,
FOREIGN KEY (StudentID) REFERENCES Student(Id),
FOREIGN KEY (ClassID) REFERENCES Class(Id),
UNIQUE (StudentID, ClassID)
);
INSERT INTO Class (Id, Name, Number)
VALUES (1, '1', 1), (2, '5', 5)
INSERT INTO Student (Id, Name)
VALUES (1, '1'), (2, '5')
INSERT INTO StudentClassRelation (StudentID, ClassID, Income)
VALUES (1, 1, 10), (2, 1, 20), (2, 2, 5)
如果您不想更改查询的其余部分,这里有一个解决方法(2 个选项)
select sum(scr.Income) from Student s
left join StudentClassRelation scr on scr.classId = s.Id
and EXISTS(select top 1 1 from Class where Class.Id = scr.classId and Class.Number > 4)
--> 5
select sum(scr.Income) from Student s
left join StudentClassRelation scr on scr.classId = s.Id
and (select top 1 Class.Number from Class where Class.Id = scr.classId) > 4
--> 5
是否按预期工作?
编辑:我的错,@GarethD 提供的解决方案更好(使用内部连接而不是左连接)
要将 StudentClassRelation
的连接保留为 LEFT JOIN
并根据 class table 中的列应用过滤器,您可以使用 LEFT JOIN
到在 Class 上使用 INNER JOIN
的子查询,例如
SELECT SUM(scr.Income)
FROM Student AS s
LEFT JOIN
( SELECT scr.StudentId, scr.Income
FROM StudentClassRelation AS scr
INNER JOIN Class AS c
ON c.Id = scr.ClassId
WHERE c.Number > 4
) AS scr
ON scr.StudentId = s.Id;
然而,您可以用一种不那么冗长的方式重写它,如下所示:
SELECT SUM(scr.Income)
FROM Student AS s
LEFT JOIN (StudentClassRelation AS scr
INNER JOIN Class AS c
ON c.Id = scr.ClassId
AND c.Number > 4)
ON scr.StudentId = s.Id;
两者的执行计划完全一致,哪个更好,完全看个人喜好,看你觉得哪个更易读。你花在阅读代码上的时间比写代码的时间还多,所以最不冗长的方法并不等同于最好的方法。
同样值得注意的是,如果这是整个查询,那么与在整个
中简单地使用 INNER JOIN
没有任何区别
SELECT SUM(scr.Income)
FROM Student AS s
INNER JOIN StudentClassRelation AS scr
ON scr.classId = s.Id
INNER JOIN Class AS c
ON c.Id = scr.classId
AND c.Number > 4;
但是既然你已经提到这是一个更大查询的一部分,我会假设它不仅仅是发布的示例,而且实际上需要 LEFT JOIN
StudentClassRelation
,例如如果您要执行以下操作:
SELECT s.Id, Income = SUM(scr.Income)
FROM Student AS s
LEFT JOIN (StudentClassRelation AS scr
INNER JOIN Class AS c
ON c.Id = scr.ClassId
AND c.Number > 4)
ON scr.StudentId = s.Id
GROUP BY s.Id;
这将产生与 INNER JOIN
和 tables
版本不同的结果
SELECT s.Id, Income = SUM(scr.Income)
FROM Student AS s
INNER JOIN StudentClassRelation AS scr
ON scr.classId = s.Id
INNER JOIN Class AS c
ON c.Id = scr.classId
AND c.Number > 4
GROUP BY s.Id;
Table Student
Id | Name |
---|---|
1 | Name |
2 | Name |
Table Classes
Id | Name | Number |
---|---|---|
1 | class1 | 2 |
2 | class1 | 3 |
和一个连接 table
StudentId | ClassId | Income |
---|---|---|
1 | 1 | 5 |
2 | 2 | 6 |
和查询
select sum(scr.Income)
from Student s
left join StudentClassRelation scr on scr.classId = s.Id
left join Class c on c.Id = scr.classId and c.Number > 4
我想将 c.Number > 4
移动到第二行,以便仅接收来自 类 且数字大于 4 的收入。我无法显着更改查询,因为它是更大的。我需要以某种方式过滤 StudentClassRelation
CREATE TABLE Student
(
Id INT PRIMARY KEY,
Name VARCHAR(100),
);
CREATE TABLE Class
(
Id INT PRIMARY KEY,
Name VARCHAR(100),
Number int
);
CREATE TABLE StudentClassRelation
(
Income int,
StudentID INT NOT NULL,
ClassID INT NOT NULL,
FOREIGN KEY (StudentID) REFERENCES Student(Id),
FOREIGN KEY (ClassID) REFERENCES Class(Id),
UNIQUE (StudentID, ClassID)
);
INSERT INTO Class (Id, Name, Number)
VALUES (1, '1', 1), (2, '5', 5)
INSERT INTO Student (Id, Name)
VALUES (1, '1'), (2, '5')
INSERT INTO StudentClassRelation (StudentID, ClassID, Income)
VALUES (1, 1, 10), (2, 1, 20), (2, 2, 5)
如果您不想更改查询的其余部分,这里有一个解决方法(2 个选项)
select sum(scr.Income) from Student s
left join StudentClassRelation scr on scr.classId = s.Id
and EXISTS(select top 1 1 from Class where Class.Id = scr.classId and Class.Number > 4)
--> 5
select sum(scr.Income) from Student s
left join StudentClassRelation scr on scr.classId = s.Id
and (select top 1 Class.Number from Class where Class.Id = scr.classId) > 4
--> 5
是否按预期工作?
编辑:我的错,@GarethD 提供的解决方案更好(使用内部连接而不是左连接)
要将 StudentClassRelation
的连接保留为 LEFT JOIN
并根据 class table 中的列应用过滤器,您可以使用 LEFT JOIN
到在 Class 上使用 INNER JOIN
的子查询,例如
SELECT SUM(scr.Income)
FROM Student AS s
LEFT JOIN
( SELECT scr.StudentId, scr.Income
FROM StudentClassRelation AS scr
INNER JOIN Class AS c
ON c.Id = scr.ClassId
WHERE c.Number > 4
) AS scr
ON scr.StudentId = s.Id;
然而,您可以用一种不那么冗长的方式重写它,如下所示:
SELECT SUM(scr.Income)
FROM Student AS s
LEFT JOIN (StudentClassRelation AS scr
INNER JOIN Class AS c
ON c.Id = scr.ClassId
AND c.Number > 4)
ON scr.StudentId = s.Id;
两者的执行计划完全一致,哪个更好,完全看个人喜好,看你觉得哪个更易读。你花在阅读代码上的时间比写代码的时间还多,所以最不冗长的方法并不等同于最好的方法。
同样值得注意的是,如果这是整个查询,那么与在整个
中简单地使用INNER JOIN
没有任何区别
SELECT SUM(scr.Income)
FROM Student AS s
INNER JOIN StudentClassRelation AS scr
ON scr.classId = s.Id
INNER JOIN Class AS c
ON c.Id = scr.classId
AND c.Number > 4;
但是既然你已经提到这是一个更大查询的一部分,我会假设它不仅仅是发布的示例,而且实际上需要 LEFT JOIN
StudentClassRelation
,例如如果您要执行以下操作:
SELECT s.Id, Income = SUM(scr.Income)
FROM Student AS s
LEFT JOIN (StudentClassRelation AS scr
INNER JOIN Class AS c
ON c.Id = scr.ClassId
AND c.Number > 4)
ON scr.StudentId = s.Id
GROUP BY s.Id;
这将产生与 INNER JOIN
和 tables
SELECT s.Id, Income = SUM(scr.Income)
FROM Student AS s
INNER JOIN StudentClassRelation AS scr
ON scr.classId = s.Id
INNER JOIN Class AS c
ON c.Id = scr.classId
AND c.Number > 4
GROUP BY s.Id;