SQL Prompt教程:旧式联接语法(ST001)

SQL Prompt是一款实用的SQL语法提示工具。SQL Prompt根据数据库的对象名称、语法和代码片段自动进行检索,为用户提供合适的代码选择。自动脚本设置使代码简单易读--当开发者不大熟悉脚本时尤其有用。SQL Prompt安装即可使用,能大幅提高编码效率。此外,用户还可根据需要进行自定义,使之以预想的方式工作。

使用旧式联接语法没有任何优势。如果SQL提示标识了它在旧版代码中的使用,则重写语句以使用ANSI标准的连接语法将简化和改进代码。

SQL Prompt实现了一个静态代码分析规则ST001,该规则将在开发和测试工作期间自动检查代码是否出现非ANSI标准的JOIN语法。

SQL的“旧样式” Microsoft / Sybase JOIN样式已使用= *和* =语法,已弃用,不再使用。当数据库引擎级别为10(SQL Server 2008)或更高版本(兼容级别100)时,使用此语法的查询将失败。ANSI-89表引用列表(FROM表A,表B)仍然仅是INNER JOIN的ISO标准。这些样式都不值得使用。自ANSI SQL-92发布以来,就一直最好指定所需的连接类型:INNER,LEFT OUTER,RIGHT OUTER,FULL OUTER和CROSS。尽管可以选择任何受支持的JOIN样式,而不会影响SQL Server使用的查询计划,但使用ANSI标准语法将使您的代码更易于理解,更一致,并且可移植到其他关系数据库系统中。

旧式外部联接已过时

当SQL Server从Sybase派生时,它继承了其旧的非标准Transact-SQL语法用于联接,其中分别包括左和右外部联接的=和=语法。

从第一个表(外部联接的“外部成员”)中选择的左外部联接运算符* =,满足语句限制的所有行。仅当该行的连接条件匹配时,第二个表(“内部成员”)才会生成值;否则,它提供空值。相反,对于右外部联接运算符= *,第二个表成为“外部成员”,从中选择所有符合条件的行。

即使支持这些语法,也存在一些限制。您不能在HAVING子句中包含Transact-SQL外部联接,也不能在与旧式外部联接相同的表达式中执行其他INNER JOIN。此外,外部连接语法(* =或= *)并不总是给出正确的结果,有时在指定外部连接时使用交叉连接。

无论如何,此语法在SQL Server 2005及更高版本中已被弃用,并在SQL Server 2008中停止工作。清单1的目的是查询pubs数据库,其目的是返回没有相应作者的所有标题。

--all titles without an author
SELECT ti.title + Coalesce( ' (' + ti.type + ') -' + ti.pub_id,' (Unknown category)') AS publication
  FROM dbo.titles AS ti, dbo.titleauthor AS Ta
     where ti.title_id *= Ta.title_id
     AND Ta.title_id IS NULL;

清单1
但是,除非将兼容性级别设置为90,否则它将在SQL Server 2008或更高版本中失败。此设置仅在SQL Server 2012之前可用:

Msg 102, Level 15, State 1, Line 6
Incorrect syntax near '*='.

如果仍然有使用此语法的查询,则在升级到SQL Server 2012之前,必须重写它们以使用清单2中所示的ANSI标准语法,因为不再支持兼容性级别90。

--all titles without an author
SELECT ti.title + Coalesce( ' (' + ti.type + ') -' + ti.pub_id,' (Unknown category)') AS publication
  FROM dbo.titles AS ti
    LEFT OUTER JOIN dbo.titleauthor AS Ta
      ON ti.title_id = Ta.title_id
  WHERE Ta.title_id IS NULL
ORDER BY ti.title

清单2

得到以下结果:

ed9be5fb2ca708aa3f5aea526deb7c1a.png

支持老式的内部联接,但没有优势

内部联接的表引用语法是ANSI标准的一部分,因此仍受支持。清单3使用了它,并将返回与其发布者居住在同一城市的所有作者。

–(旧语法)与发布者居住在同一城市的作者

  --(Old Syntax)authors that live in the same city as their publishers
SELECT 
  authors.au_fname + ' ' + authors.au_lname AS Author, 
  publishers.pub_name AS Publisher, publishers.city
  FROM dbo.authors, dbo.titleauthor, dbo.titles, dbo.publishers
  WHERE authors.au_id = titleauthor.au_id 
    AND titleauthor.title_id = titles.title_id 
    AND titles.pub_id = publishers.pub_id 
    AND publishers.city = authors.city

清单3

清单4显示了使用ANSI-92标准的相同代码,其中我们使联接类型明确。

--(Newer Syntax) authors that live in the same city as their publishers
SELECT 
  authors.au_fname+ ' '+authors.au_lname AS Author, 
  publishers.pub_name AS Publisher, publishers.city
  FROM dbo.authors
    INNER JOIN dbo.titleauthor
      ON authors.au_id = titleauthor.au_id
    INNER JOIN dbo.titles
      ON titleauthor.title_id = titles.title_id
    INNER JOIN dbo.publishers
      ON titles.pub_id = publishers.pub_id
  WHERE publishers.city = authors.city

清单4

两者给出的结果相同,执行计划相同。

25a17466de637f0a2d936ce8c31df39f.png

但是,广泛接受的是,旧式的“引文列表”内部联接语法很难阅读和理解,因此比新语法更容易出错。

无论如何,即使仍支持该旧式语法,也没有遗憾的理由。例如,您如何使用旧风格的联接语法确定与发布者居住在不同城市的作者所占的百分比?这将是一个使用方括号和子查询的外观复杂的查询。使用更新的语法,它很容易编写,也很容易理解其逻辑。

--proportion of authors who live in the same city as their publishers
SELECT 
  Sum(CASE WHEN publishers.city IS NULL THEN 1 ELSE 0 END) AS [different city],
  Count(*) AS total, 
  (Sum(CASE WHEN publishers.city IS NULL THEN 1 ELSE 0 END) * 100)
      / Count(*) AS percentage
  FROM dbo.authors
    INNER JOIN dbo.titleauthor
      ON authors.au_id = titleauthor.au_id
    INNER JOIN dbo.titles
      ON titleauthor.title_id = titles.title_id
    LEFT OUTER JOIN dbo.publishers
      ON titles.pub_id = publishers.pub_id AND publishers.city = authors.city

清单5

结论

将旧式联接语法留在遗留代码中没有任何优势。如果发现此代码异味,它将改进并简化代码以重写语句以使用ANSI标准连接语法


如果您对SQL Prompt感兴趣,可以在慧都网免费下载最新试用版

猜你喜欢

转载自blog.51cto.com/15078157/2669355
今日推荐