
你真的會玩SQL嗎?之邏輯查詢處理階段
最近要對數據庫進行優化,但由于工作項目中已經很少親自寫SQL而且用的都不是很復雜的語句,所以有些生疏了,于是翻翻N年前的筆記資料,想以此來記錄回顧總結一些實用的SQL干貨讓大家來學習,若有不對之處可提出。
記得剛出來行走江湖的時候也是只會增、刪、改、查四大法寶,一般公司沒有多少復雜的業務,所以就夠用了。但后來看著大神會寫個幾百行的SQL存儲過程就感覺自己是不是弱爆了。
如今是大數據的時代,對數據的處理要求越來越重視,要出各種數據報表,因此百萬數據處理速度,數據庫明顯比后臺邏輯處理的優勢不是一個別。
在此我想再次提示一個數據處理的中心思想,SQL數據處理是集合思維,不要用邏輯思維來思考。
文中的示例來自自己的積累和TSQL2008技術內幕。
基礎知識普及
對于教條式的定義請自己去查,此處不會涉及到文鄒鄒的知識,但還是強調一下基礎的重要性,即使你理解了所有的概念,但當組合起來用時也會一頭霧水。
邏輯查詢處理階段
在以上的10個處理步驟中, 每一步的處理都生成一個虛擬表來作為下一步的輸入. 虛擬表對于調用者或輸出查詢來說是不存在的, 僅在最后步驟生成的表才會返回給調用者或者輸出查詢. 如果某一子句沒有出現在SQL語句中, 這一步就被簡單跳過..
這10個具體步驟是:
1.FROM: from子句中的兩個表首先進行交叉連接(笛卡爾積), 生成虛擬表VT1。
2.ON:
on條件作用在VT1上, 將條件為True的行生成VT2。
3.OUTER: 如果outer join被指定, 則根據外連接條件,
將左表or右表or多表的未出現在VT2查詢結果中的行加入到VT2后生成VT3。
4.WHERE: VT3表中應用Where條件,
結果為真的行用來生成VT4。
5.GROUP BY: 根據Group by指定的列, 將VT4的行組織到不同的組中,
生成VT5。
6.CLUB|ROLLUP: 超級組(分組之后的分組)被添加到VT5中, 生成VT6。
7.HAVING: Having用來篩選組,
VT6上符合條件的組將用來生成VT7。
8.SELECT: select子句用來選擇指定的列, 并生成VT8。
9.DISTINCT:
從VT8中刪除重復的行后, VT9被生成。
10.ORDER BY: 根據Order by子句, VT9中的行被排序, 生成游標10。
注意事項:
第一步中FROM: 需要對兩表同時存在的列添加前綴, 以免混淆.
第二步中ON: 在SQL特有的三值邏輯(true,false,unknown)中, unkown的值也是確定的, 只是在不同情況下有時為true, 有時為false. 一個總的原則是: unknown的值非真即假, 非假即真. 也就是時說, unknown只能取true和false里面的一個值, 但是unknown的相反還是unknown.如:
在ON、WHERE和HAVING中做過濾條件時, unknown看做false;
在CHECK約束中, unknown被看做是true;
在條件中, 兩個NULL的比較結果還是Unknown.
在UNIQUE和PRIMARY KEY約束、排序和分組中, NULL被看做是相等的. 例如Group by 將null分為一組, 而order by將所有null排在一起.
第三步中OUTER: 如果多余兩張表, 則將VT3和FROM中的下一張表再次執行從第一步到第三步的過程.
第四步中WHERE: 由于此刻沒有分組, 也沒有執行select所以, where子句中不能寫分組函數, 也不能使用表的別名. 并且, 只有在外連接時, on和where的邏輯才是不同的, 因此建議連接條件放在on中.
第五步中GROUP BY: 如果查詢中包含Group by 子句, 那么所有的后續操作(having, select等)都是對每一組的結果進行操作.
Group by子句中可以使用組函數, 在Sql 2000中一旦使用組函數, 其后面的步驟將都不能處理, 而在
Sql2005中沒有這個限制.
第六步不常用, 略過.
第七步中HAVING: having表達式是僅有的分組條件. 注意: count(*)不會忽略掉null, 而count(field)會; 此外分組函數中不支持子查詢做輸入.
第八步中SELECT: 如果包含Group By子句, 那么在第5步后將只能使用Group By子句中出現的列, 如果要使用其他原始列則, 只能使用組函數.
另外, select在第八步才執行, 因此別名只能第八步之后才能使用, 并且只能在order by中使用.
第九步中DISTINCT: 當使用Group By子句時, 使用Distinct是多余的, 他不會刪除任何記錄.
第十步中ORDER BY: 按Order by子句指定的列排序后, 返回游標VC10.
別名只能在Order by子句中使用.
如果定義了Distinct子句, 則只能排序上一步中返回的表VT9, 如果沒有指定Distinct子句, 則可以排序不再最終結果集中的列. 例如: 如果不加Distinct則Order by可以訪問VT7和VT8中的內容.
這一步最不同的是它返回的是游標而不是表, Sql是基于集合論的, 集合中的元素師沒有順序的, 一個在表上引用Order by排序的查詢返回一個按照特定特定物理順序組織的對象—游標. 所以對于視圖、子查詢、派生表等均不能將order by結果作為其數據來源.
建議: 使用表的表達式時, 不允許使用order by子句的查詢, 因此除非你真的要對行排序, 否則不要使用order by 子句.
內容為 RJ 寫的,邏輯非常清楚,值得花點時間理解,再次強調是因為復雜的集合數據處理過程中會得到不是你想要的結果,這時就要你自己腦袋當SQL處理器來推出結果查出問題,可能大多數寫了幾年的SQL都還沒弄明白,但到了用時還是提前理解下,非常重要。
練習
/*1.返回來自美國的客戶,并為每個客戶返回其訂單總數和商品交易總數量。
涉及到表:Sales.Customers表、Sales.Orders表,以及Sales.OrderDetails表。
期望的輸出:
*/
custid numorders totalqty
----------- ----------- -----------
32 11 345
36 5 122
43 2 20
45 4 181
48 8 134
55 10 603
65 18 1383
71 31 4958
75 9 327
77 4 46
78 3 59
82 3 89
89 14 1063
1參考SQL:
--answer:
select c.custid,count(distinct o.orderid) as 'numorders',sum(od.qty) as 'totalqty'
from Sales.Customers as c
join Sales.Orders as o
on c.custid=o.custid
join Sales.OrderDetails as od
on o.orderid=od.orderid
where c.country='USA'
group by c.custid
/*
1.將表Sales.Customers別名為c和表Sales.Orders別名為o應用ON篩選器以custid為條件內連接,生成虛擬表VT1,
2.將虛擬表VT1和表Sales.OrderDetails應用ON篩選器以orderid為條件內連接,生成虛擬表VT2,
3.對上一步返回的虛擬表中的所有行應用where篩選器返回滿足條件c.country='USA'的虛擬表VT3,
4.應用group by子句將數據以c.custid列分組
5.處理select列表,去掉重復o.orderid再用count統計個數返回別名為numorders的列,統計od.qty列別名totalqty
*/
/*2:返回客戶及其訂單信息,包括沒有下過任何訂單的客戶。
涉及到表:Sales.Customers和Sales.Orders表。
期望的輸出(按簡略的格式顯示):
*/
custid companyname orderid orderdate
----------- --------------- ----------- ------------------------
85 Customer ENQZT 10248 2006-07-04 00:00:00.000
79 Customer FAPSM 10249 2006-07-05 00:00:00.000
34 Customer IBVRG 10250 2006-07-08 00:00:00.000
84 Customer NRCSK 10251 2006-07-08 00:00:00.000
...
73 Customer JMIKW 11074 2008-05-06 00:00:00.000
68 Customer CCKOT 11075 2008-05-06 00:00:00.000
9 Customer RTXGC 11076 2008-05-06 00:00:00.000
65 Customer NYUHS 11077 2008-05-06 00:00:00.000
22 Customer DTDMN NULL NULL
57 Customer WVAXS NULL NULL
2參考SQL:
--answer:
select c.custid,c.companyname,o.orderid,o.orderdate
from Sales.Customers as c
left join Sales.Orders as o
on c.custid=o.custid
/*
1.將表Sales.Customers別名為c和表Sales.Orders別名為o應用ON篩選器以custid為條件左外連接,生成虛擬表VT1,
2.添加外部行,外部行中非保留表中的屬性被賦值為NULL,生成虛擬表VT2
3.處理select列表,查找出c.custid,c.companyname,o.orderid,o.orderdate生成虛擬表VT3
*/
/*3:返回值2007年2月12日下過訂單的客戶,以及他們的訂單。同時也返回在2007年2月12日沒有下過訂單的客戶。
涉及到表:Sales.Customers表和Sales.Orders表。
期望的輸出(按簡略格式顯示):
*/
custid companyname orderid orderdate
----------- --------------- ----------- -----------------------
72 Customer AHPOP NULL NULL
58 Customer AHXHT NULL NULL
25 Customer AZJED NULL NULL
18 Customer BSVAR NULL NULL
91 Customer CCFIZ NULL NULL
...
33 Customer FVXPQ NULL NULL
53 Customer GCJSG NULL NULL
39 Customer GLLAG NULL NULL
16 Customer GYBBY NULL NULL
4 Customer HFBZG NULL NULL
5 Customer HGVLZ 10444 2007-02-12 00:00:00.000
42 Customer IAIJK NULL NULL
34 Customer IBVRG NULL NULL
63 Customer IRRVL NULL NULL
73 Customer JMIKW NULL NULL
15 Customer JUWXK NULL NULL
...
21 Customer KIDPX NULL NULL
30 Customer KSLQF NULL NULL
55 Customer KZQZT NULL NULL
71 Customer LCOUJ NULL NULL
77 Customer LCYBZ NULL NULL
66 Customer LHANT 10443 2007-02-12 00:00:00.000
38 Customer LJUCA NULL NULL
59 Customer LOLJO NULL NULL
36 Customer LVJSO NULL NULL
64 Customer LWGMD NULL NULL
29 Customer MDLWA NULL NULL
...
3參考SQL:
--answer:
select c.custid,c.companyname,o.orderid,o.orderdate
from Sales.Customers as c
left join Sales.Orders as o
on c.custid=o.custid
and o.orderdate='2007-2-12'
/*
1.將表Sales.Customers別名為c和表Sales.Orders別名為o應用ON篩選器以custid和o.orderdate='2007-2-12'為條件左外連接,生成虛擬表VT1,
2.添加外部行,外部行中非保留表中的屬性被賦值為NULL,生成虛擬表VT2
3.處理select列表,從虛擬表VT2中查找出c.custid,c.companyname,o.orderid,o.orderdate生成虛擬表VT3
*/
數據分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
2025 年,數據如同數字時代的 DNA,編碼著人類社會的未來圖景,驅動著商業時代的運轉。從全球互聯網用戶每天產生的2.5億TB數據, ...
2025-05-27CDA數據分析師證書考試體系(更新于2025年05月22日)
2025-05-26解碼數據基因:從數字敏感度到邏輯思維 每當看到超市貨架上商品的排列變化,你是否會聯想到背后的銷售數據波動?三年前在零售行 ...
2025-05-23在本文中,我們將探討 AI 為何能夠加速數據分析、如何在每個步驟中實現數據分析自動化以及使用哪些工具。 數據分析中的AI是什么 ...
2025-05-20當數據遇見人生:我的第一個分析項目 記得三年前接手第一個數據分析項目時,我面對Excel里密密麻麻的銷售數據手足無措。那些跳動 ...
2025-05-20在數字化運營的時代,企業每天都在產生海量數據:用戶點擊行為、商品銷售記錄、廣告投放反饋…… 這些數據就像散落的拼圖,而相 ...
2025-05-19在當今數字化營銷時代,小紅書作為國內領先的社交電商平臺,其銷售數據蘊含著巨大的商業價值。通過對小紅書銷售數據的深入分析, ...
2025-05-16Excel作為最常用的數據分析工具,有沒有什么工具可以幫助我們快速地使用excel表格,只要輕松幾步甚至輸入幾項指令就能搞定呢? ...
2025-05-15數據,如同無形的燃料,驅動著現代社會的運轉。從全球互聯網用戶每天產生的2.5億TB數據,到制造業的傳感器、金融交易 ...
2025-05-15大數據是什么_數據分析師培訓 其實,現在的大數據指的并不僅僅是海量數據,更準確而言是對大數據分析的方法。傳統的數 ...
2025-05-14CDA持證人簡介: 萬木,CDA L1持證人,某電商中廠BI工程師 ,5年數據經驗1年BI內訓師,高級數據分析師,擁有豐富的行業經驗。 ...
2025-05-13CDA持證人簡介: 王明月 ,CDA 數據分析師二級持證人,2年數據產品工作經驗,管理學博士在讀。 學習入口:https://edu.cda.cn/g ...
2025-05-12CDA持證人簡介: 楊貞璽 ,CDA一級持證人,鄭州大學情報學碩士研究生,某上市公司數據分析師。 學習入口:https://edu.cda.cn/g ...
2025-05-09CDA持證人簡介 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度、美團、阿里等 ...
2025-05-07相信很多做數據分析的小伙伴,都接到過一些高階的數據分析需求,實現的過程需要用到一些數據獲取,數據清洗轉換,建模方法等,這 ...
2025-05-06以下的文章內容來源于劉靜老師的專欄,如果您想閱讀專欄《10大業務分析模型突破業務瓶頸》,點擊下方鏈接 https://edu.cda.cn/g ...
2025-04-30CDA持證人簡介: 邱立峰 CDA 數據分析師二級持證人,數字化轉型專家,數據治理專家,高級數據分析師,擁有豐富的行業經驗。 ...
2025-04-29CDA持證人簡介: 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度,美團,阿里等 ...
2025-04-28CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-27數據分析在當今信息時代發揮著重要作用。單因素方差分析(One-Way ANOVA)是一種關鍵的統計方法,用于比較三個或更多獨立樣本組 ...
2025-04-25