Inner Join vs Natural Join vs USING子句:有什么优势吗?

Man*_*ngo 6 sql join

想象一下,我有两个简单的表,例如:

CREATE TABLE departments(dept INT PRIMARY KEY, name);
CREATE TABLE employees(id PRIMARY KEY, fname, gname,
    dept INT REFERENCES departments(dept));
Run Code Online (Sandbox Code Playgroud)

(当然简化).

我可以有以下任何陈述:

SELECT * FROM employees e INNER JOIN departments d ON e.dept=d.dept;
SELECT * FROM employees e NATURAL JOIN departments d;
SELECT * FROM employees e JOIN departments d USING(dept);
Run Code Online (Sandbox Code Playgroud)

可以在这里找到一个工作示例:SQL Fiddle:http://sqlfiddle.com/#!15/864a5/13/10

它们都给出了几乎相同的结果 - 当然是相同的行.

我一直更喜欢第一种形式,因为它具有灵活性,可读性和可预测性 - 你清楚地定义了什么与什么有关.

现在,除了第一种形式有重复的列之外,其他两种形式是否真的有优势?或者他们只是语法糖?

我可以看到后一种形式的缺点是你应该命名你的主键和外键相同,这并不总是实用的.

phi*_*pxy 5

现在,除了第一种形式有重复的列这一事实之外,其他两种形式是否有真正的优势?或者它们只是语法糖?

TL;DR NATURAL JOIN 用于某种关系编程风格,它比通常的 SQL 风格更简单。(虽然当嵌入 SQL 时,它会背负其余的 SQL 查询语法。)那是因为 1. 它直接使用谓词逻辑简单运算符,工程(包括软件工程),科学(包括计算机科学)中的精确语言和数学,而且 2.同时交替直接 使用关系代数简单运算符。

关于 NATURAL JOIN 的常见抱怨是,由于共享列不是明确的,因此在架构更改后可能会出现不适当的列配对。在特定的开发环境中可能就是这种情况。但在这种情况下,有一个要求,只有某些列进行连接和自然连接无项目是不恰当的。因此,这些论点假定NATURAL JOIN 使用不当。此外,争论者甚至不知道他们忽略了要求。这样的抱怨是似是而非。(此外,健全的软件工程设计原则导致没有与此类规范的接口。)

来自同一阵营的另一个相关的误解似是而非的抱怨是“NATURAL JOIN 甚至没有考虑外键关系”。但是任何连接都存在是因为表的含义,而不是约束。查询不需要约束。如果添加了约束,则查询保持正确。如果删除了约束,那么依赖它的查询就会出错,必须更改为依赖它的措辞,而不必更改。这与 NATURAL JOIN 无关。


您已经描述了效果上的差异:只返回每个公共列的一个副本。

是否有任何经验法则可以根据人类可读的描述构造 SQL 查询?

事实证明,自然语言表达式和逻辑表达式以及关系代数表达式和 SQL 表达式(后两者的混合)以一种相当直接的方式对应。

例如来自Codd 1970

所描述的关系称为component。[...]组件( x , y , z )的含义是零件x是零件y的直接组件(或子组件),并且需要零件x 的z 个单元来组装零件y 的一个单元。

这个答案

每个基表都有一个语句模板,又名predicate,由列名参数化,我们通过它放入或删除一行。

将一行插入谓词给出了一个语句又名命题。提出真命题的行放在表中,提出假命题的行留在表中。(所以一个表格陈述了每个当前行的命题,而不陈述每个缺席行的命题。)

但是每个表表达式值的每个表达式都有一个谓词。关系模型的设计使得如果表TU保存 T(...) 和 U(...)(分别)的行,则:

  • T NATURAL JOIN U 保存 T(...) AND U(...) 的行
  • T WHEREcondition保存 T(...) AND条件的行
  • T UNION CORRESPONDING U 保存 T(...) 或 U(...) 的行
  • T EXCEPT CORRESPONDING U 保存 T(...) AND NOT U(...) 的行
  • SELECT DISTINCTcolumns to keepFROM T保存存在
    THERE EXISTS列的以删除T(...)
  • 等等

而关于 SQL 的推理是......不是“自然的”:

SQL SELECT 语句可以在代数上被认为是 1. 隐式地C将表的每一列与(可能是隐式的)相关名称重命名TT.C,然后 2. CROSS JOINing,然后 3. RESTRICTing per INNER ON,然后 4. RESTRICTing per WHERE,然后5. 按 SELECT 进行投影,然后 6. 按 SELECT 重命名,删除T.s,然后 7. 隐式重命名以删除剩余的T.s 在T.-RENAMEings之间的代数运算符也可以被认为是逻辑运算符和表名作为它们的谓词:T JOIN ...vs Employee T.EMPLOYEE has name T.NAME ... AND ...。但从概念上讲,SELECT 语句内部是一个双重重命名诱导 CROSS JOIN 表,其中T.Cs 表示列名,而外部表则有Cs 表示列名。

或者,SQL SELECT 语句在逻辑上可以被认为是 1.FORSOME T IN E围绕每个相关名称T和基本名称或子查询引入整个语句E,然后 2.T通过使用T.C引用其C部分来引用quantified 的值,然后 3. 构建结果行from T.Cs per FROM etc,然后 4. 根据 SELECT 子句命名结果行列,然后 4. 离开FORSOMEs的范围。代数运算符再次被认为是逻辑运算符和表名作为它们的谓词。尽管如此,这在概念上有T.C内部 SELECT ,但C外部有相关名称来来往往。

这两种 SQL 解释远不及可互换使用 JOIN 或 AND 等简单。(您不必同意它更简单,但这种看法就是为什么 NATURAL JOIN 和 UNION/EXCEPT CORRESPONDING 存在的原因。)(在其预期用途之外批评这种风格的论点是似是而非。)

USING 是一种中间地带孤儿,一只脚在 NATURAL JOIN 阵营,一只脚在 CROSS JOIN。它在前者中没有实际作用,因为那里没有重复的列名。在后者中,它或多或少只是缩写 JOIN 条件和 SELECT 子句。

我可以看到后一种形式的缺点是您应该将主键和外键命名为相同的名称,这并不总是实用的。

查询不需要 PK(主键)、FK(外键)和其他约束。(知道一列是其他人的函数允许标量子查询,但你总是可以不使用。)此外,任何两个表都可以有意义地连接。如果您需要两列与 NATURAL JOIN 具有相同的名称,您可以通过 SELECT AS 重命名。