为什么这两个 SQL 查询不做同样的事情?

Why don't these two SQL queries do the same thing?

以下来自黑客排名SQL(基本)认证来自本页,https://www.hackerrank.com/skills-verification

块 1


SELECT ei.employee_ID, ei.name
FROM employee_information AS ei, Last_quarter_bonus AS lqb
WHERE ei.division = 'HR'
AND lqb.bonus >= 5000;

区块 2

SELECT ei.employee_ID, ei.name
FROM employee_information AS ei, Last_quarter_bonus AS lqb
WHERE ei.division = 'HR'
AND lqb.bonus >= 5000
AND ei.employee_ID = lqb.employee_id;

这两个查询之间的唯一区别是最后一行,BLOCK 2 的第 5 行:

AND ei.employee_ID = lqb.employee_id;

但我不知道为什么需要那一行。 在我看来,第一段代码应该可以正常编译。 我不明白第5行的必要性是什么。 在我看来,第 3 行和第 4 行已经使第 5 行为真,而无需编写第 5 行。

那么,为什么我必须编写第 5 行才能让查询按照我想要的方式进行编译?
为什么这两个查询吐出不同的结果?

这是使用显式 JOIN 的 BLOCK 2 查询。这是评论中提到的首选语法。

SELECT ei.employee_ID, ei.name
FROM employee_information AS ei JOIN Last_quarter_bonus AS lqb
    ON ei.employee_ID = lqb.employee_ID
WHERE ei.division = 'HR' AND lqb.bonus >= 5000;

这里的条件是在ON子句中指定的。需要此条件才能仅包含雇员与 employee_informationlast_quarter_bounus.

相同的行

AND ei.employee_ID = lqb.employee_id;

But i dont know why that line is necessary.

这一行表示连接条件。 查询涉及 2 tables,如您在 FROM 子句中所见。 table 名称之间的逗号将导致 CROSS JOIN(在这种情况下可能不那么明显,因为只有一个逗号)。

第二个查询使用 INNER JOIN,这也不明显,因为 FROM 子句看起来与第一个查询相同(table 名称,逗号 -> 交叉连接)。但是,条件 ei.employee_ID = lqb.employee_id 强制执行内部联接,这将减少结果集中的行数。

为了SQL代码更清晰,很多人推荐内连接使用JOIN ... ON ...语法,交叉连接使用CROSS JOIN语法

等效项:

-- use this
select *
from ei cross join lqb ;

-- avoid
select *
from ei, lqb ;

对于内连接...

-- use this
select *
from ei join lqb on ei.id = lqb.id ;

-- avoid
select *
from ei, lqb
where ei.id = lqb.id ;

您可以看到,在内部连接的情况下,如果您只使用 table 的列表(即 table 名称和逗号),WHERE 子句将因连接条件而变得混乱在 FROM 子句中(您加入的 table 越多,这种效果就越差)。

DBfiddle here.

第五行必须的。在这个问题中,它要求您查看两个 table 并编写一个语句来过滤输出以显示 HR 中的任何员工并获得 5000 或更多的奖金。

抛开语法偏好,

当您在第二块中执行此操作时,与第一块中的两个相比,您需要寻找三个条件。你有:

  • 寻找在hr工作的员工的条件(ei.division = 'HR')
  • 寻找奖金达到或超过 5000 的员工的条件 (lqb.bonus >= 5000) 和
  • 将两个 table 联系在一起的条件 (ei.employee_ID = lqb.employee_id)。

因为 SQL 很笨,所以你必须准确地告诉它你想让它做什么。如果不关联两个 table 就无法关联两个搜索。

如果您将所有这些信息集中在一个 table 中,您将能够使用块 1 中的两个条件(无需连接)并获得您正在寻找的结果但是因为有两个table,所以你必须把它包括进去。

现在关于语法,当您声明一个联接时,您通常指定哪个列在两个 table 之间共享。因此,如果您要使用连接编写此语句,则最后一个条件将被烘焙到连接命令中,而不是位于底部(SELECT * FROM database1 AS db1 JOIN database2 AS db2 ON db1.commonColumn= db2.commonColumn)。这将使它看起来像这样:

SELECT ei.employee_ID, ei.name       // columns to display
FROM employee_information AS ei      // first table to look at
JOIN Last_quarter_bonus AS lqb       // second table to look at
ON ei.employee_ID = lqb.employee_id  // shared column between both tables
WHERE ei.division = 'HR'             // condition 1
AND lqb.bonus >= 5000;               // condition 2

当然代码的结构应该更加精简,但我在语句中为每个动作换行,这样我可以更好地解释每个组件的作用。