2008技术内幕:T-SQL语言基础 联接查询摘记
?
續 2008技術內幕:T-SQL語言基礎 單表查詢摘記
第三章?聯接查詢
Microsoft SQL Server 2008 支持四種表運算符 join(ANSI標準)、apply(T-SQL擴展)、pivot(T-SQL擴展)、unpivot(T-SQL擴展)。
(ANSI SQL是美國國家標準學會(ANSI) 對SQL進行規范化后的國際標準SQL語言,T-SQL是Microsoft SQL Server基于ANSI SQL做了一些擴展形成的專用SQL語言。)
join表運算符對兩個輸入表進行操作,有三種基本類型:交叉聯接、內聯接、外聯接。
處理步驟:
交叉聯接只有一個步驟--笛卡爾積;
內聯接有兩個步驟--笛卡爾積、過濾;
外聯接有三個步驟--笛卡爾積、過濾、添加外部行。
出于優化的目的,SQL Server關系引擎經常會采用很多處理捷徑(數據庫引擎并沒有嚴格按照邏輯查詢處理步驟),因為他知道這樣的處理仍然能夠生成正確的結果。
?
交叉聯接:
SQL Server支持交叉聯接的兩種標準語法--ANSI SQL-92 和 ANSI SQL-89 推薦用ANSI SQL-92(下面有推薦說明)。?
--ANSI SQL-92標準 CROSS JOIN 關鍵字 SELECT c.custid ,e.empid FROM Sales.Customers AS cCROSS JOIN hr.Employees AS e --ANSI SQL-89標準 SELECT c.custid ,e.empid FROM Sales.Customers AS c ,hr.Employees AS e這兩種語法在邏輯上和性能上都沒有區別,Customers表有91行而Employees有9行數據,所以上面的查詢會生成一個819行數據的結果集。
笛卡爾積:如果一個表有m行,而另個表有n行,將得到m*n行的結果集。
圖11
自交叉聯接:顧名思義一個表實現自己連接自己。交叉聯接、內鏈接、外連接都支持自聯接。上面笛卡爾積圖就是一個自交叉聯接實例。?
SELECT E1.empid ,E1.firstname ,E1.lastname ,E2.empid ,E2.firstname ,E2.lastname FROM hr.Employees AS E1CROSS JOIN hr.Employees AS E2在自聯接中,必須為表起別名,如果不為表指定別名,聯接結果中的列名就會有歧義。?
--利用自聯接生成數字表 DECLARE @table TABLE(digit INT NOT NULL PRIMARY KEY) INSERT INTO @table( digit )VALUES ( 0 ),( 1 ),( 2 ),( 3 ),( 4 ),( 5 ),( 6 ),( 7 ),( 8 ),( 9 )SELECT T1.digit + T2.digit * 10 + T3.digit * 100 + 1 AS d FROM @table AS T1CROSS JOIN @table AS T2CROSS JOIN @table AS T3 ORDER BY d?
內聯接
兩個邏輯步驟:一,對兩個輸入的表進行笛卡爾積運算,二,過濾。
?--ANSI SQL-92標準
兩表之間必須指定inner join關鍵字,inner關鍵字是可選的,因為內聯接是默認的聯接方式,可以單獨指定join關鍵字。?
on條件子句和where、having子句一樣,只返回結果為true的行,而不會返回謂詞計算結果為false、unknow的行
--ANSI SQL-89標準SELECT e.empid ,e.firstname ,e.lastname ,o.orderid FROM hr.Employees AS e ,Sales.Orders AS o WHERE e.empid = o.empid?
語法推薦說明
在這里,還是強烈推薦使用ANSI SQL-92標準的聯接語法,因為在某些方面它用起來更安全。如果你寫一條內聯接查詢但忘記了指定聯接條件,如果這時候用的是ANSI SQL-92標準,查詢語句將是無效的,語法分析器會報錯。即使錯誤提示信息沒有馬上指出錯誤是缺少了聯接條件,但最終還是可以想辦法找到問題在哪,修改好查詢語句。
而ANSI SQL-89語法,如果忘記了指定聯接條件,查詢仍然是有效的,執行的結果集卻是一個交叉查詢。
?錯誤例子?
SELECT e.empid ,e.firstname ,e.lastname ,o.orderid FROM hr.Employees AS eJOINJOIN Sales.Orders AS o錯誤:Incorrect syntax near 'o'.? 如果使用的是ANSI SQL-89標準語法,忘記了寫連接條件,?
SELECT e.empid ,e.firstname ,e.lastname ,o.orderid FROM hr.Employees AS e ,Sales.Orders AS o那么恭喜得了一個大數據的大獎!爽歪歪!邏輯一復雜,錯誤在哪里也不知。
堅持推薦使用ANSI-92的原因:
1.是保持一致性(都有關鍵字)
2.減少錯誤(以防邏輯條件被遺漏)
3.提高維護性(一個寫好的存儲過程,你也不知道會被后面的人改幾次,本來是個交叉聯接改來改去成了內聯接!這個是你無法預算的,但是這是可避免,直接標明cross join.)
?
組合聯接:就是聯接條件涉及兩邊多個列的查詢?
SELECT * FROM tabName1 AS AINNER JOIN tabName2 AS B ON A.id1 = B.idAND A.id = B.id2?
不等聯接:如果聯接條件只包含等號運算符,那么這樣的聯接叫做等值聯接,如果聯接條件包含除等號以外的其他運算符,那么這樣的聯接叫做不等聯接。?
SELECT * FROM tabName1 AS AINNER JOIN tabName2 AS B ON A.id1 > B.id?
多表聯接
一個聯接表運算符只對兩個表進行操作,而一條查詢語句可以包含多個聯接。
通常,當From子句中包含多個表運算符時,表運算符在邏輯上是按從左到右的順序處理的。?
SELECT c.custid ,c.companyname ,o.orderid ,od.productid ,od.qtyFROM Sales.Customers AS cINNER JOIN Sales.Orders AS o ON c.custid = o.custidINNER JOIN Sales.OrderDetails AS od ON o.orderid = od.orderid?
外聯接
外聯接是在ANSI SQL-92中才被引入的,因此它只有一種標準語法。邏輯步驟:笛卡爾積、on過濾、添加外部行。
在外聯接中,要把一個表標記為“保留的”表,可以在表名之間使用關鍵字 left outer join、right outer join、full outer join,其中outer關鍵字是可選的(left join 、right join、full join )。
left關鍵字表示左邊的表的行是保留的,right關鍵字表示右邊表的行是保留的,full關鍵字則表示左右兩邊表的行都是保留的。對于來自聯接的非保留表的那些列,追加的外部行中的這些列則用null作為占位符。
SELECT C.custid ,C.companyname ,O.orderid FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON C.custid = O.custid?
題目:查詢訂單表中所有訂單,查出從2007年1月1日到2010年12月12日之間的每個日期輸訂單個數。
DECLARE @table TABLE([num] INT NOT NULL PRIMARY KEY ,[date] DATETIME NOT NULL) SET NOCOUNT ON DECLARE @i INT= 1 BEGIN TRAN WHILE ( @i <= 3000 ) BEGININSERT INTO @table( num, date )VALUES ( @i, -- num - intDATEADD(DAY, @i - 1, '20060101') -- date - datetime ) ;SET @i = @i + 1 ;END COMMIT TRAN SET NOCOUNT OFFSELECT CAST(d.date AS DATE) AS [date] ,COUNT(o.orderid) AS [count] FROM @table AS DLEFT JOIN Sales.Orders AS O ON CAST(d.date AS DATE) = CAST(o.orderdate AS DATE) WHERE CAST(d.date AS DATE) BETWEEN '20070101'AND '20101212' GROUP BY CAST(d.date AS DATE)思路:
--1 建立一個輔助表,往里面添加數據,從2006年1月1日到2014年03月17日
--2 利用外聯接查詢
?
ISNULL()函數
語法
isnull(check_expression,replacement_value) returns int
?
SELECT [date] ,ISNULL(orderid, 0) AS 'default' ,orderid FROM @table AS DLEFT JOIN Sales.Orders AS O ON CAST(d.date AS DATE) = CAST(o.orderdate AS DATE)圖
?
外聯接的條件過濾
對外聯接表中非保留表的列值進行過濾,這通常就是存在錯誤的一個標志。因為外聯接得到的外部行中的值有可能是null,而null<運算符><值>運算,得到的只會是Unknow。
例子
?
SELECT c.custid ,c.companyname ,o.orderid ,o.orderdate FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON C.custid = O.custid WHERE O.orderdate >= '20070101'上面這條查詢語句是對Customers表和Orders表執行左聯接操作,Customers作為保留表,在where條件篩選之前,o.orderdate是有兩條為null的值使用O.orderdate >= '20070101'過濾條件后,直接將這兩條剔除了,因為null和任何比較都是unknow,而where只支持邏輯值為true的表達式,這樣的查詢條件會讓所有外部行都被過濾掉,效果上相當于抵消了外聯接的作用,換句話說,這里就是把外聯接當成內聯接用了。
?
練習
1-1.執行以下代碼?
?
1-2 寫一條查詢語句,把所有雇員記錄復制5次。
SELECT empid ,firstname ,lastname ,n FROM HR.Employees AS ECROSS JOIN dbo.Nums AS T WHERE n < = 5?
1-3 寫一個查詢,為每個雇員從2009年06月12日致2009年6月12日范圍內的每天返回一行。
SELECT H.empid ,DATEADD(DAY, n - 1, '20090101') AS [date] FROM dbo.Nums AS NCROSS JOIN HR.Employees AS H WHERE DATEADD(DAY, n - 1, '20090101') BETWEEN '20090612'AND '20090616' ORDER BY h.empid?
2.返回來自美國的客戶,并為每個客戶返回其訂單總數和商品交易總數量。
SELECT C.custid ,COUNT(DISTINCT O.orderid)AS [count] ,SUM(OD.qty) AS totalqty FROM Sales.Customers AS CINNER JOIN Sales.Orders AS O ON C.custid = O.custidINNER JOIN Sales.OrderDetails AS OD ON O.orderid = OD.orderid WHERE C.country = 'USA' GROUP BY C.custid?
3.返回客戶及其訂單信息,包括沒有下過任何訂單的客戶.
SELECT c.custid ,c.companyname ,o.orderid ,o.orderdate FROM Sales.Customers AS CLEFT JOIN Sales.Orders AS O ON C.custid = O.custid?
4.返回在2007年02月12日下過訂單的客戶,以及他們的訂單,同時也返回在2007年2月12日沒有下過訂單的客戶.
SELECT c.custid ,c.companyname ,o.orderid ,o.orderdate FROM Sales.Customers AS CLEFT JOIN ( SELECT custid ,orderid ,orderdateFROM Sales.OrdersWHERE CAST(orderdate AS DATE) = '20070212') AS O ON C.custid = O.custid圖
5.返回所有客戶信息,并根據客戶是否在2007年2月12日日下過訂單,再為每個客戶返回一列 Yes/No值。上一題的擴展。用case when
SELECT c.custid ,c.companyname ,CASE WHEN o.orderid IS NULL THEN 'No'ELSE 'Yes'END HasOrderOn20070212 FROM Sales.Customers AS CLEFT JOIN ( SELECT custid ,orderid ,orderdateFROM Sales.OrdersWHERE CAST(orderdate AS DATE) = '20070212') AS O ON C.custid = O.custid?
轉載于:https://www.cnblogs.com/Jolinson/p/3605753.html
總結
以上是生活随笔為你收集整理的2008技术内幕:T-SQL语言基础 联接查询摘记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sorted_一个函数秒杀冒泡排序算法和
- 下一篇: CMD下查询Mysql中文乱码的解决方法