如何在连接中使用 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;