繁体   English   中英

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

[英]SQL Joins: Future of the SQL ANSI Standard (where vs join)?

我们正在开发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作业。

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

除了马克的观点:

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

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

但是使用较新的连接语法有很多原因。 其中:

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

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

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

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

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

只要他们没有使用*** =和= *作为他们的连接语法( 从SQL Server 2008 R2开始就被弃用 ),从长远来看,我看不到它会消失,但正如Mark Byers所说,有很多理由不去做。

我最大的担忧是,如果他们正在写加入这个样子, 还有什么是他们这样做非常规?

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

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

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

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

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

     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; 

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM