SQL连接:SQL ANSI标准的未来(vs加入)?

时间:2010-09-10 11:33:02

标签: sql sql-server sql-server-2008 join ansi-sql

我们正在开发ETL工作,我们的顾问在加入表时一直使用“旧式”SQL

select a.attr1, b.attr1
from table1 a, table2 b
where a.attr2 = b.attr2

而不是使用内连接子句

select a.attr1, b.attr1
from table1 as a inner join table2 as b
   on a.attr2 = b.attr2

我的问题是,从长远来看,是否存在使用旧“加入”的风险?这种连接支持多长时间并保持为ANSI标准?我们的平台是SQL Server,我的主要原因是将来不再支持这些“where join”。发生这种情况时,我们必须使用“内连接”连接方式修改所有ETL作业。

9 个答案:

答案 0 :(得分:8)

为什么不担心你现在面临的风险,而不是担心未来可能面临的风险?

除了马克的观点:

  • 当连接表中断开ON子句(有时是多行)时,代码难以阅读(从而理解其目的)。这会增加修改代码时出错的可能性。
  • 确定正在进行何种类型的JOIN更难 - 您必须浏览WHERE子句并希望您所看到的是正确的。
  • 查找缺少的JOIN子句更加困难,增加了无意中的笛卡尔连接的风险 - 当您使用ANSI语法时,ON子句很好地排列,使这个变得微不足道。

答案 1 :(得分:7)

我怀疑“哪里加入”将不受支持。它不可能不支持它们,因为它们基于笛卡尔积和简单的滤波。它们实际上不是连接。

但是有很多理由使用较新的连接语法。其中包括:

  • 可读性
  • 可维护性
  • 更容易更改为外连接

答案 2 :(得分:4)

有很多理由可以避免隐式连接。最重要的是:

  • 无法轻易更改为外部联接。
  • 使用隐式连接更容易忘记连接条件。
  • 如果混合使用隐式和显式联接,则会出现混淆优先级的问题。这是几小时前的一个例子:MySQL Syntax error

我认为不会很快将它们删除,但还有很多其他原因可以停止使用它们。

答案 3 :(得分:3)

最新版本的ISO SQL(2003,2008)支持这两种语法。使用逗号在FROM子句中指定交叉连接是完全标准的SQL,并且我遇到的所有SQL产品都支持它。它似乎不太可能在SQL中被弃用或不被支持。

答案 4 :(得分:2)

只要他们没有使用*** =和= *作为他们的连接语法(已经deprecated as of SQL Server 2008 R2),从长远来看,我看不到它会消失,但作为Mark Byers他说,有很多理由不去做。

我最担心的是,如果他们正在写这样的联接,那么 else 他们做的那是非常规的吗?

答案 5 :(得分:1)

很难说某种语法结构的优雅或丑陋。你只是看到它或不看。逗号分隔的连接语法反映了Relational Algebra的基本特征,它断言了select-project-join查询的正常形式。唯一一种逃避它的连接(因此,保证专用语法)是外连接。丢失等式的意外错误断言渲染连接图不相交只是前端SQL编程工具的复杂程度(它是否显示连接图?)。

这不仅仅是美学。生产数据库通常在许多表中包含CREATED_ON或COMMENTS等列。在这种情况下,NATURAL JOIN语法很危险。

正如Anthony Molinaro(流行的“SQL Cookbook”的作者)雄辩地说:“旧式短小,甜美而完美。 ANSI愚弄了它,对于那些已经开发了一段时间的人来说,完全没必要“。

答案 6 :(得分:1)

人们有一些好处,但到目前为止还有两个没有被提及的大点:

  1. 旧样式* =和= *外连接是否给出了正确的结果,它们也无法正确表示某些连接。请考虑以下查询。我们希望向所有未订购超过100美元的客户展示:

    SELECT
    FROM
       Customer C
       LEFT JOIN Order O ON C.OrderID = O.OrderID AND O.OrderTotal >= 100.0;
    WHERE
       O.OrderID IS NULL;
    

    尝试并表达旧方式......如果可以的话。不使用派生表。

  2. 对我来说,使用正确的连接子句的重要价值在于,从 this 的特殊过滤器中分离标准连接条件(几乎每个涉及这两个表的查询都会应用)将返回所需行的查询:

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

    这种分离意味着查看查询的开发人员在扫描此查询的区别时不必处理一堆混乱。如果他熟悉这些表,他可以完全跳过FROM子句,只需读取WHERE子句即可获得所需的所有信息。它更快。如果你不关心更快,即使只是用你的眼球扫描查询,我也不想和你合作。

    现在对于那些认为在使用JOIN语法时所有内容都有一些特殊之处的人来说,你错了。以下查询与上层查询一样好:

    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;
    

    此查询甚至可能具有完全相同的执行计划。惊讶吗?不要。就像旧式语法一样,优化器是负责根据您给出的条件确定如何连接表的方法。只要它们没有引用尚未提及的表格,条件的位置并不重要。

  3. 那两种风格之间的最大区别是什么?如果您认为上面的第二个混淆查询难以理解并且是一种疯狂的写作方式,那么,您自然会认为旧的查询风格是蹩脚的。因为坦率地说,把所有条件随意地放在任何旧地方都是杂乱无章的。 JOIN的组织系统是有道理的。如果你习惯了旧式并且不喜欢新款式,那可能是因为改变是令人不愉快的(对我们所有人来说)。但是一旦你使用它一段时间,我相信它会在你身上发展。至少,如果没有,我不可能理解为什么。

答案 7 :(得分:0)

左右连接暗示语法* =和= *已被弃用,并且有充分理由,它目前不会始终返回正确的结果。如果他们已经使用过这个,那么现在必须修复它们,因为它们目前会让您面临不正确结果的风险。这不是一个选择。另一种语法将继续有效,但由于多种原因也应予以替换。首先,很容易得到意外的交叉连接,这可能会返回不良结果,或者通过使用不同的结果来修复,这可能会产生性能问题。

另一个问题是维护。如果人们稍后在查询中添加其他联接并再次开始混合隐含和显式联接,则可能会得到错误的结果,甚至不知道它。在代码库中留下这种糟糕的代码是非常非常糟糕的。隐含联接也很难理解,因为它们通常由不了解联接的开发人员编写,但它们可能不是您所需要的。如果在查询中存在交叉连接,那么维护者如何知道它是否是一个错误(以及偶然的交叉连接)或故意的交叉连接(我们偶尔会真正需要它们)。我不接受这样编写的代码。我会坚持认为写这篇文章的无能者,无需额外费用即可修复它。

答案 8 :(得分:-2)

如果您担心将从标准版或SQL产品中删除它们,请不要担心。它不可能永远发生。

这种“旧式”的加入就是:只是一种风格问题。那些喜欢它的人发誓,有些情况下“旧式”连接更容易理解。虽然我并不完全相信自己,但有一件事是肯定的:不时会遇到旧式连接,并且重新设计代码以适合您自己的个人风格并不总是合适的。因此,习惯风格并学会使用它。