我在大约7000行T-SQL存储过程中有我的业务逻辑,并且其中大多数具有下一个JOIN语法:

将用以下查询替换此类查询:

SELECT A.A, B.B, C.C
FROM aaa AS A, bbb AS B, ccc AS C
WHERE
    A.B = B.ID
AND B.C = C.ID
AND C.ID = @param


还是相同的?

评论

我不知道您为什么编辑标题:它现在包含错误陈述。这两个查询都是联接,并且它们各自的语法都包含在SQL-92标准中。请注意,除美国(ANSI)之外,该标准还属于国际(ISO)。

摘自Wikipedia上有关SQL的文章:“ SQL于1986年被美国国家标准协会(ANSI)用作SQL-86,并于1987年被国际标准化组织(ISO)采用。”在文献中,限定词ISO / IEC似乎比ANSI更为普遍。我认为ANSI在诸如Stackoverflow之类的论坛中很普遍,因为诸如SQL Server和MySQL之类的产品具有使用单词“ ANSI”的关键字,例如ANSI_NULLS(我不知道为什么他们不使用“ ISO”);尽管这些是我自己的观察,但我怀疑它们是原始思想;)

还要注意,每个标准都采用(并添加了)以前的标准SQL的功能,因此永不弃用标准SQL的功能,休·达尔文(Hugh Darwen)称之为兼容性的ckle锁。

您可以通过阅读每个标准的规范来证明上述内容;)关于两个查询都是标准SQL的证明:请使用Mimer SQL-92验证程序:一次将每个查询复制并粘贴到框中,进行编辑以删除专有SQL服务器语法@param(例如,将其更改为文字值1),然后单击“测试SQL”。两者都将生成结果“ Transitional SQL-92”。

您可以分别使用SQL-99验证器和[SQL:2003验证器](developer.mimer.com/validator/parser200x/index.tml)重复上述操作。我假设您不是要我证明它们都是联接并且在语义上是等效的,这是任何一半像样的优化器都应该认识到的事实,因为在接受的答案中已注明。

#1 楼

这两个查询是相同的,除了第二个查询是ANSI-92 SQL语法,第一个查询是未合并join子句的较旧的SQL语法。尽管您可能需要检查,但它们应该产生完全相同的内部查询计划。

出于多种原因,应使用ANSI-92语法


JOIN子句的使用将
关系逻辑与
过滤器逻辑(WHERE)分离开,因此
更干净,更容易理解。
与此无关紧要查询,但是在某些情况下,较旧的外部联接语法(使用+)含糊不清,因此查询结果与实现有关,或者根本无法解析查询。 ANSI-92不会发生这种情况。
这是一个好习惯,因为大多数开发人员和dba如今将使用ANSI-92,因此您应该遵循该标准。当然,所有现代查询工具都会生成ANSI-92。如@gbn所指出的那样,它的确可以避免意外的交叉连接。

我自己在一段时间内一直抵制ANSI-92。与旧语法相比,它在概念上有一点点优势,因为将SQL设想为对所有使用的表进行大规模笛卡尔连接,然后进行过滤操作是一种较容易的想法-一种心理技术,对于掌握SQL查询的工作很有用。但是,几年前,我决定需要与时俱进,经过相对较短的调整后,我现在非常喜欢这样做-主要是因为上面提到的第一个原因。唯一应该脱离ANSI-92语法或者不使用该选项的地方是自然连接,这是隐式的危险。

评论


10年前,我也有类似的倾向,那就是放弃旧的逗号/等号形式的联接,但并没有回头。

–拉里·史密斯(Larry Smith)
15年5月14日在21:34

检查大型查询时,查看紧密靠近相关表的联接逻辑会很有帮助。较旧的语法可能需要大量上下滚动才能一起检查表和谓词。

– durette
17年6月26日在16:07

作为避免交叉连接的进一步说明,显式连接使在通过复合键进行连接时更容易发现丢失的谓词。当大型组合键的最后一列的基数非常低时,这样的谓词缺失可能会在特殊情况下引发隐患,因此在测试过程中它们并不总是很明显。更清晰的语法使这些问题在开发时更加明显。

– durette
17年6月26日在16:13

#2 楼

第二种构造在SQL社区中称为“固定连接语法”。第一个构造AFAIK没有广泛接受的名称,因此我们将其称为“旧样式”内部联接语法。

通常的参数如下:

'传统'语法:
谓词在WHERE子句中以物理形式组合在一起,无论按什么顺序排列(通常使查询,尤其是n元关系)更易于阅读和理解(该子句的ON子句固定语法可以扩展谓词,因此您必须在可视距离内查找一个表或列的外观。

“传统”语法的缺点:省略一个语法不会出现解析错误'join'谓词的结果,结果是笛卡尔乘积(在后缀语法中称为CROSS JOIN),这种错误很难检测和调试。同样,“ join”谓词和“ filtering”谓词在WHERE子句中物理分组在一起,这可能导致它们彼此混淆。

#3 楼

好,他们执行相同。同意。
与许多其他惯例不同,我使用的是较旧的惯例。 SQL-92的“易于理解”值得商bat。我已经写了40年的编程语言(大嘴),我知道“易读”首先要以“视觉敏锐度”(在这里使用了错误的术语,但这是我可以使用的最好的短语),然后才是其他惯例。阅读SQL时,您首先要关心的是涉及哪些表,然后是哪个表(最)定义了粒度。然后,您要关注数据的相关约束,然后是所选的属性。尽管SQL-92大多将这些想法分开,但杂乱无章的单词太多了,心灵不得不解释和处理这些单词,这使得读取SQL的速度变慢。

SELECT Mgt.attrib_a   AS attrib_a
      ,Sta.attrib_b   AS attrib_b
      ,Stb.attrib_c   AS attrib_c
FROM   Main_Grain_Table  Mgt
      ,Surrounding_TabA  Sta
      ,Surrounding_tabB  Stb
WHERE  Mgt.sta_join_col  = Sta.sta_join_col
AND    Mgt.stb_join_col  = Stb.stb_join_col
AND    Mgt.bus_logic_col = 'TIGHT'


视觉敏锐度!
将逗号放在新属性的前面,这也使注释代码更容易
对函数和关键字使用特定的大小写
对表使用特定的大小写
使用属性的特定情况
垂直排列运算符和操作
使FROM中的第一张表代表数据的粒度
使WHERE的第一张表成为联接约束,让特定的严格约束浮动到最底端。
为数据库中的所有表选择3个字符的别名,并在引用该表时使用别名EVERYWHERE。您也应该使用该别名作为该表上(许多)索引的前缀。
1 1/2打中的6打,对吧?也许。但是,即使您使用的是ANSI-92约定(按照我的经验,并且在某些情况下还会继续使用),都使用视敏度原理,通过垂直对齐可以使您的视线避开您想看的地方,并轻松避开事物(尤其是杂音)不需要。

#4 楼

同时执行并检查其查询计划。它们应该相等。

评论


+1以使用分析工具。我建议查看:了解指定联接的更多“充满糖分”的方式。让标准作为指导,但请记住,您的特定DB实现是路径(并且希望它不是MySQL :)

–user166390
09-10-21在6:43

#5 楼

这两个查询相等-第一个查询使用非ANSI JOIN语法,第二个查询使用ANSI JOIN语法。我建议坚持使用ANSI JOIN语法。

是的,当有可能要连接的表时,您想使用LEFT OUTER JOINs(btw也是ANSI JOIN语法)。可能不包含任何匹配的记录。

参考:SQL Server中的条件联接

#6 楼

在我看来,FROM子句是我决定要在其上执行SELECT子句的行中需要哪些列的地方。在此表达业务规则的地方将把计算所需的值带到同一行。业务规则可以是拥有发票的客户,从而导致包含负责客户的发票行。也可能是与客户使用相同邮政编码的场所,从而产生了场所和客户之间紧密联系的列表。毕竟,我们仅显示了RDBMS中一个列表的隐喻,每个列表都有一个主题(实体),而每一行都是该实体的实例。如果了解行中心性,则了解结果集的实体。

WHERE子句在概念上在from子句中定义行之后执行,它会剔除SELECT子句可以使用的不需要的行(或包括必需的行)。

因为连接逻辑可以在FROM子句和WHERE子句中表示,并且由于存在子句以划分和征服复杂的逻辑,所以我选择将涉及值的连接逻辑放在FROM子句中的列中,因为这从本质上讲表示匹配列中的值所支持的业务规则。

ie我不会这样写WHERE子句:

 WHERE Column1 = Column2


我将其放在FROM子句中,如下所示:

 ON Column1 = Column2


同样,如果要将一列与外部值(可能在列中或不在列中的值)进行比较(例如将邮政编码与特定的邮政编码进行比较),则将其放在WHERE子句中,因为本质上说我只想要这样的行。

ie我不会写这样的FROM子句:

 ON PostCode = '1234'


我将其放在WHERE子句中,如下所示:

 WHERE PostCode = '1234'


评论


ON AND PostCode ='1234'在有条件联接的左联接上很有用,但不能排除具有PostCode <>'1234'的行

–bummi
14-10-18在22:35

#7 楼

ANSI语法不会强制将谓词放置在正确子句(即ON或WHERE)中,也不会强制ON子句与相邻表引用的亲和力。开发人员可以自由编写这样的烂摊子

SELECT
   C.FullName,
   C.CustomerCode,
   O.OrderDate,
   O.OrderTotal,
   OD.ExtendedShippingNotes
FROM
   Customer C
   CROSS JOIN Order O
   INNER JOIN OrderDetail OD
      ON C.CustomerID = O.CustomerID
      AND C.CustomerStatus = 'Preferred'
      AND O.OrderTotal > 1000.0
WHERE
   O.OrderID = OD.OrderID;


谈到“将生成ANSI-92”的查询工具,我在这里评论,因为它生成了

SELECT 1
   FROM DEPARTMENTS C
        JOIN EMPLOYEES A
             JOIN JOBS B
     ON C.DEPARTMENT_ID = A.DEPARTMENT_ID
     ON A.JOB_ID = B.JOB_ID


唯一摆脱常规“限制项目-笛卡尔积”的语法是外部联接。此操作更复杂,因为它不关联(既不关联,也不关联)。至少必须明智地用外部联接将查询括起来。但是,这是一个奇特的操作。如果您经常使用它,建议您使用关系数据库类。

评论


我认为您的第二个示例语法无效。

–超立方体ᵀᴹ
2012-4-18 23:42

我看不到外部联接是一个“异国”操作。

– a_horse_with_no_name
15年6月18日在12:45