想象一下,我有两个简单的表,例如:
CREATE TABLE departments(dept INT PRIMARY KEY, name);
CREATE TABLE employees(id PRIMARY KEY, fname, gname,
dept INT REFERENCES departments(dept));
(当然简化)。
我可以有以下任何陈述:
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);
可在此处找到一个工作示例:SQL Fiddle: http://sqlfiddle.com/#!15/864a5/13/10
他们都给出了几乎相同的结果 - 当然是相同的行。
由于其灵活性,可读性和可预测性,我一直更喜欢第一种形式 - 你清楚地定义了什么与什么有关。
现在,除了第一个表单有重复列的事实之外,其他两个表单是否真的有优势?或者他们只是语法糖?
我可以看到后一种形式的缺点是你应该将你的主键和外键命名为相同,这并不总是实用的。
答案 0 :(得分:3)
现在,除了第一个表单有重复列的事实之外,其他两个表单是否真的有优势?或者他们只是语法糖?
TL; DR NATURAL JOIN用于某种类型的关系编程,它比通常的SQL风格更简单。 (虽然当嵌入在SQL中时,它会使用其余的SQL查询语法。)这是因为1.它直接使用的简单运算符谓词逻辑 ,工程(包括软件工程),科学(包括计算机科学)和数学的精确语言,而且2. 同时和或 直接使用 关系代数 的简单运算符。
关于NATURAL JOIN的常见抱怨是,由于共享列不是显式的,因此在架构更改后可能会发生不适当的列配对。在特定的开发环境中可能就是这种情况。但在这种情况下,有一个要求 只有某些列被连接而NATURAL JOIN没有PROJECT 是不合适的。所以这些参数假设天然JOIN被不恰当地使用。此外,争辩者甚至不知道他们忽略了要求。这种抱怨似是而非。 (此外,合理的软件工程设计原则导致没有与这些特定的接口。)
来自同一阵营的另一个相关误解的似是而非的抱怨是"NATURAL JOIN does not even take foreign key relationships into account"。但是any join is there because of the table meanings, not the constraints。查询不需要约束。如果添加约束,则查询保持正确。如果删除约束,则依赖 不必更改。这与NATURAL JOIN无关。
您已经描述了效果上的差异:只返回每个公共列的一个副本。
来自Is there any rule of thumb to construct SQL query from a human-readable description?:
事实证明,自然语言表达式和逻辑表达式以及关系代数表达式和SQL表达式(后两者的混合)以相当直接的方式对应。
例如来自Codd 1970:
描述的关系称为组件。 [...] 组件( x , y , z )的含义是部分x 是部件 y 的直接组件(或子组件),组件 x 的 z 单元需要组装一个单元部分 y 。
来自this answer:
每个基表都有一个语句模板,也就是谓词,通过列名参数化,我们通过这些模板放入一行或将其遗漏。
将一行插入谓词会给出一个声明,即命题。构成真命题的行进入表中,并且构成错误命题的行不会出现。 (因此,表格列出了每个当前行的命题,并且没有说明每个缺席行的命题。)
但每个表的表达式值每个表达式都有一个谓词。设计关系模型,以便如果表
T
和U
包含T(...)和U(...)(分别)的行,则:
T NATURAL JOIN U
包含T(...)和U(...)T WHERE
condition
包含T(...)AND 条件 T UNION CORRESPONDING U
包含T(...)或U(...)T EXCEPT CORRESPONDING U
包含T(...)AND NOT U(...)SELECT DISTINCT
columns to keep
FROM T
保留行所在的行
那里有列要删除 SUCH THAT T(...)然而,关于SQL的推理是......不是"自然":
SQL SELECT语句可以被认为是代数为1.隐式地将表的每个列C
重新命名为T
到T.C
,然后是2. {CROSS} JOINING,然后3.RINTRING INING INNER ON,然后4. RESTRICTing每WHERE,然后5. PROJECTing每个SELECT,然后6.RENAMEing每个SELECT,删除T.
s,然后7.隐式重新放置以删除剩余{{1在T.
- RENAMEings之间的代数运算符也可以被认为是逻辑运算符和表名作为它们的谓词:T.
vs T JOIN ...
。但概念上,在SELECT语句中是一个双RENAME引发的CROSS JOIN表,其中Employee T.EMPLOYEE has name T.NAME ... AND ...
用于列名,而外表有T.C
个用于列名。
或者,可以将SQL SELECT语句逻辑地视为1.在每个相关名C
和基本名称或子查询FORSOME T IN E
的整个语句周围引入T
,然后2.引用通过使用E
引用其T
部分,然后3.根据FROM等从T.C
构建结果行,然后4.命名结果,量化C
的值每个SELECT子句的行列,然后4.离开T.C
的范围。同样,代数运算符被认为是逻辑运算符和表名作为它们的谓词。尽管如此,这在概念上在SELECTs中有FORSOME
但在T.C
之外有相关名称来来去去。
这两个SQL解释远不如使用JOIN或AND等,可互换那么简单。 (你不必同意它更简单,但这种看法是为什么有天然加入和联合/除非相应的原因。)(在其预期用途范围之外批评这种风格的论据是似是而非的。)
USING是一种中间孤儿孤儿,一只脚在NATURAL JOIN营地,另一只在CROSS JOIN。它在前者中没有真正的作用,因为那里没有重复的列名。在后者中,它或多或少只是缩写JOIN条件和SELECT子句。
我可以看到后一种形式的缺点是你应该将你的主键和外键命名为相同,这并不总是实用的。
PKs(主键),FK(外键)&查询不需要其他约束。 (知道列是其他函数的函数允许标量子查询,但是你总是可以没有短语。)此外,任何两个表都可以有意义地连接起来。如果您需要两列与NATURAL JOIN具有相同的名称,则可以通过SELECT AS重命名。
答案 1 :(得分:1)
默认情况下,键入JOIN会执行INNER JOIN。 所以:
SELECT * FROM employees e INNER JOIN departments d USING(dept);
相当于
SELECT * FROM employees e JOIN departments d USING(dept);
并且结果中只有一个dept列。
以同样的方式
SELECT * FROM employees e INNER JOIN departments d ON e.dept=d.dept;
相当于
SELECT * FROM employees e JOIN departments d ON e.dept=d.dept;
但结果中会有一个重复的dept列。
INNER JOIN
更易于阅读,尤其是如果您的查询中包含其他联接类型(LEFT或RIGHT或..)。
NATURAL JOIN
假定两个表匹配中的同名列。因此,如果例如在employees表中,您的连接列被命名为" department"那么您就不能执行NATURAL JOIN
。在您的部门表中,您的连接列名为" dept"
答案 2 :(得分:1)
NATURAL JOIN
的一个主要优势是它是唯一一个不会生成重复列的SQL连接。
如果从SQL语言中删除了除NATURAL JOIN
以外的所有联接类型,则它仍然是关系完整的。 NATURAL JOIN
是您需要的唯一联接类型。
但是,在SQL92之前,NATURAL JOIN
没有引入SQL。在SQL的早期阶段,语言设计者选择其他连接类型,因此必须找到一种处理重复列的方法。
考虑
的结果employees e CROSS JOIN departments d
涉及两列名为dept
的列,因为每个表都有一个列名dept
,即'重复列'。
选择重复列的解决方案'问题是上面示例中的范围变量e
和d
。 [大多数SQL民众称它们为表别名',这是cnfusing,因为范围变量代表行,而不是表格)。 SQL标准将它们称为“相关名称”,但不清楚“相关性”是什么'在上下文中意味着Chris Date和LINQ称他们为范围变量,我也是如此!]使用'遗产'连接类型和省略范围变量,将使用等于表格名称的范围变量名称(可能是'表aiias' fallacy?的根。)。
使用OP的例子:
SELECT * FROM employees e INNER JOIN departments d ON e.dept=d.dept;
投影SELECT *
将包含重复列'。列的名称及其在结果中的排序是SQL标准未尝试解决的问题之一;尝试标准化已经有太多不同的实现。在SQL Server中,我得到重复的名称[叹气]。
可能出于这些原因,大多数SQL人员说,"从不使用SELECT *
&#34;通常的方法是指定每一列和“项目”。任何重复。 [我认为SELECT ALL BUT <set of columns>
功能很不错,但我认为SQL民众赢了一天。]
使用NATURAL JOIN
时,没有&#39;重复列&#39;去远离&#39;并且没有连接谓词,因此不需要范围变量。所以OP的例子应该改写为:
SELECT * FROM employees NATURAL JOIN departments;
虽然确实如果一个人专门使用NATURAL JOIN
并且避开所有其他连接类型,那么不再需要范围变量,SQL有时仍需要它们。使用@ philipxy的方案,&#34;如果您需要两列与NATURAL JOIN
具有相同的名称,则可以通过SELECT AS
&#34;重命名。 - 如果您的SQL实现缺少公用表表达式并且您不得不在派生表中执行重命名,那么SQL需要为派生表分配一个范围变量,即使您再也不会引用它!。
Lwt说,OP示例中的每个表格都有一个无意义的guid
列,人们需要将其投射出去。用于NATURAL JOIN
目的:
SELECT *
FROM ( SELECT dep, name, FROM employees ) e
NATURAL JOIN ( SELECT dept, fname, gname departments ) d;
在这种情况下,如果没有范围变量e
和d
,则SQL将无效(您将获得解析错误)。 SQL实现不需要范围变量(即使它确实可以在内部生成占位符!)但是SQL语言需要它们,因为SQL的兼容性sha没有删除或弃用任何功能的地方。
答案 3 :(得分:0)
NATURAL JOIN是一个JOIN操作,它根据要连接的两个表中的公共列为您创建隐式连接子句。公共列是两个表中具有相同名称的列。
NATURAL JOIN可以是INNER联接,LEFT OUTER联接或RIGHT OUTER联接。默认为INNER连接。
条款
TableA JOIN tableB USING(column)
如你所说,只是
的语法糖TableA JOIN tableB ON tableA.column = tableB.column
答案 4 :(得分:0)
NATURAL JOIN
不受广泛支持,JOIN USING
也不支持(即不在SQL Server中)
有很多关于NATURAL JOIN的论据是一个坏主意。就个人而言,我认为没有明确命名连接等事情会引发灾难。
例如,如果您在表中添加一列而没有意识到它恰好适合“自然连接”,那么当自然连接突然完全不同时,您可能会遇到意外的代码失败。您认为添加一个列不会破坏任何内容,但它可以打破写得不好的视图和自然连接。
当你构建一个系统时,你永远不应该允许这些风险进入。它与在多个表中创建视图相同,而不是每列都有一个表别名,并且使用不带列的插入列表。
由于这些原因,如果您现在只是学习SQL,那么 out 习惯使用它们。