SQL Prompt教程:舊式聯接語法(ST001)

SQL Prompt是一款實用的SQL語法提示工具。SQL Prompt根據數據庫的對象名稱、語法和代碼片斷自動進行檢索,爲用戶提供合適的代碼選擇。自動腳本設置使代碼簡單易讀--當開發者不大熟悉腳本時尤爲有用。SQL Prompt安裝便可使用,能大幅提升編碼效率。此外,用戶還可根據須要進行自定義,使之以預想的方式工做。數據庫

使用舊式聯接語法沒有任何優點。若是SQL提示標識了它在舊版代碼中的使用,則重寫語句以使用ANSI標準的鏈接語法將簡化和改進代碼。app

SQL Prompt實現了一個靜態代碼分析規則ST001,該規則將在開發和測試工做期間自動檢查代碼是否出現非ANSI標準的JOIN語法。ide

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語法用於聯接,其中分別包括左和右外部聯接的=和=語法。編碼

從第一個表(外部聯接的「外部成員」)中選擇的左外部聯接運算符* =,知足語句限制的全部行。僅當該行的鏈接條件匹配時,第二個表(「內部成員」)纔會生成值;不然,它提供空值。相反,對於右外部聯接運算符= *,第二個表成爲「外部成員」,從中選擇全部符合條件的行。spa

即便支持這些語法,也存在一些限制。您不能在HAVING子句中包含Transact-SQL外部聯接,也不能在與舊式外部聯接相同的表達式中執行其餘INNER JOIN。此外,外部鏈接語法(* =或= *)並不老是給出正確的結果,有時在指定外部鏈接時使用交叉鏈接。3d

不管如何,此語法在SQL Server 2005及更高版本中已被棄用,並在SQL Server 2008中中止工做。清單1的目的是查詢pubs數據庫,其目的是返回沒有相應做者的全部標題。
orm

--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感興趣,能夠在慧都網免費下載最新試用版

相關文章
相關標籤/搜索