我正在阅读有关 SQL 连接的 NATURAL 速记形式的信息,我看到了一些陷阱:
- 它只是自动使用所有相同的命名列对(使用 USING 指定显式列列表)
- 如果添加了一些新列,则连接输出也可能“意外”更改,这在复杂结构中可能不那么明显(即使您知道 NATURAL 是如何工作的)
我正在阅读有关 SQL 连接的 NATURAL 速记形式的信息,我看到了一些陷阱:
NATURAL JOIN
语法是反模式:
因此,我不建议在任何环境中使用该语法。
我也不推荐混合语法(即:同时使用NATURAL JOIN
和显式的 INNER/OUTER JOIN 语法)——保持一致的代码库格式。
这些似乎反对自然连接的“陷阱”是双向的。假设您在表 A 中添加一个新列,并完全期望它用于与表 B 连接。如果您知道 A 和 B 的每个连接都是自然连接,那么您就完成了。如果每个连接都明确使用 USING,那么您必须全部跟踪并更改它们。错过一个,有一个错误。
当表的语义表明这是正确的做法时,请使用 NATURAL 联接。当您想确保以特定方式完成连接时,请使用显式连接条件,而不管表定义如何演变。
对我来说完全破坏的一件事是NATURAL
我的大多数表都有一个id
列,这些列显然在语义上都是不同的。您可能会争辩说 auser_id
比 更有意义id
,但是您最终会写出诸如user.user_id
违反 DRY 之类的东西。此外,按照相同的逻辑,您还会有类似user_first_name
, user_last_name
, user_age
... 的列(考虑到它与例如 , 不同,这也是有道理的session_age
)... 恐怖。
我会坚持我的JOIN ... ON ...
,非常感谢。:)
我同意其他发帖者的观点,即为了清楚起见,应该使用显式连接,并且如果您的要求发生变化,也可以轻松地切换到“外部”连接。
但是,您的大多数“陷阱”与连接无关,而是使用“SELECT *”而不是显式命名您需要“SELECT a.col1、a.col2、b.col1、b.col2”的列的弊端。只要使用通配符列列表,就会出现这些陷阱。
添加上述任何答案中未列出的额外原因。在 postgres 中(不确定其他数据库是否是这种情况)如果在使用时在两个表之间没有找到共同的列名,则执行NATURAL JOIN
a CROSS JOIN
。这意味着,如果您有一个现有的查询,然后您随后更改了表中的一个列名,您仍然会从查询中返回一组行,而不是错误。相反,如果您使用该JOIN ... USING(...)
语法,如果连接列不再存在,您将收到错误消息。
postgres 文档对此有注释:
注意: USING 对于连接关系中的列更改是相当安全的,因为仅组合了列出的列。NATURAL 的风险要大得多,因为对任一关系的任何模式更改都会导致出现新的匹配列名称,这也会导致连接合并该新列。
你的意思是这样的语法:
SELECT *
FROM t1, t2, t3 ON t1.id = t2.id
AND t2.id = t3.id
与此相反:
SELECT *
FROM t1
LEFT OUTER JOIN t2 ON t1.id = t2.id
AND t2.id = t3.id
我更喜欢第二种语法,并且格式也不同:
SELECT *
FROM T1
LEFT OUTER JOIN T2 ON T2.id = T1.id
LEFT OUTER JOIN T3 ON T3.id = T2.id
在这种情况下,很清楚我要加入哪些表以及我使用什么 ON 子句来加入它们。通过使用第一个语法太容易了,无法放入正确的 JOIN 并获得巨大的结果集。我这样做是因为我容易出现拼写错误,这是我的保险。另外,它在视觉上更容易调试。