10個(gè)簡(jiǎn)單步驟,帶你完全理解SQL(收藏)

作者:Linary
鏈接:https://www.cnblogs.com/lina-zhang/p/3761409.html

多年前收藏在筆記中的一篇文章考润,今天偶然翻出,重讀了一遍读处,依然大有收獲糊治。分享出來(lái),大家一起探討罚舱。

以本文是為了以下讀者而特地編寫(xiě)的:

  1. 在工作中會(huì)用到 SQL 但是對(duì)它并不完全了解的人井辜。
  2. 能夠熟練使用 SQL 但是并不了解其語(yǔ)法邏輯的人揖赴。
  3. 想要教別人 SQL 的人。

本文著重介紹 SELECT 句式抑胎。

1、SQL 是一種聲明式語(yǔ)言

首先要把這個(gè)概念記在腦中:“聲明”渐北。SQL 語(yǔ)言是為計(jì)算機(jī)聲明了一個(gè)你想從原始數(shù)據(jù)中獲得什么樣的結(jié)果的一個(gè)范例阿逃,而不是告訴計(jì)算機(jī)如何能夠得到結(jié)果。sql的執(zhí)行引擎會(huì)根據(jù)你聲明的數(shù)據(jù)結(jié)果去獲取對(duì)應(yīng)的數(shù)據(jù)赃蛛。

SELECT 
first_name,
last_name
FROM employees
WHERE salary > 100000

上面的例子很容易理解恃锉,我們不關(guān)心這些雇員記錄從哪里來(lái),我們所需要的只是工資大于10W的員工呕臂。

我們從哪兒學(xué)習(xí)到這些破托?

如果 SQL 語(yǔ)言這么簡(jiǎn)單,那么是什么讓人們“聞 SQL 色變”歧蒋?

主要的原因是:我們潛意識(shí)中的是按照命令式編程的思維方式思考問(wèn)題的土砂。就好像這樣:“電腦,先執(zhí)行這一步谜洽,再執(zhí)行那一步萝映,但是在那之前先檢查一下是否滿(mǎn)足條件 A 和條件 B ”。例如阐虚,用變量傳參序臂、使用循環(huán)語(yǔ)句、迭代实束、調(diào)用函數(shù)等等奥秆,都是這種命令式編程的思維慣式。

2咸灿、SQL 的語(yǔ)法并不按照語(yǔ)法順序執(zhí)行

SQL 語(yǔ)句有一個(gè)讓大部分人都感到困惑的特性构订,就是:SQL 語(yǔ)句的執(zhí)行順序跟其語(yǔ)句的語(yǔ)法順序并不一致。SQL 語(yǔ)句的語(yǔ)法順序是:

SELECT [DISTINCT]
FROM
WHERE
GROUP BY
HAVING
UNION
ORDER BY

為了方便理解析显,上面并沒(méi)有把所有的 SQL 語(yǔ)法結(jié)構(gòu)都列出來(lái)鲫咽,但是已經(jīng)足以說(shuō)明 SQL 語(yǔ)句的語(yǔ)法順序和其執(zhí)行順序完全不一樣,就以上述語(yǔ)句為例谷异,其執(zhí)行順序?yàn)椋?/p>

FROM
WHERE
GROUP BY
HAVING
SELECT
DISTINCT
UNION
ORDER BY

關(guān)于 SQL 語(yǔ)句的執(zhí)行順序分尸,有三個(gè)值得我們注意的地方:

  1. FROM 才是 SQL 語(yǔ)句執(zhí)行的第一步,并非 SELECT 歹嘹。數(shù)據(jù)庫(kù)在執(zhí)行 SQL 語(yǔ)句的第一步是將數(shù)據(jù)從硬盤(pán)加載到數(shù)據(jù)緩沖區(qū)中箩绍,以便對(duì)這些數(shù)據(jù)進(jìn)行操作。
  2. SELECT 是在大部分語(yǔ)句執(zhí)行了之后才執(zhí)行的尺上,嚴(yán)格的說(shuō)是在 FROM 和 GROUP BY 之后執(zhí)行的材蛛。理解這一點(diǎn)是非常重要的圆到,這就是你不能在 WHERE 中使用在 SELECT 中設(shè)定別名的字段作為判斷條件的原因。
SELECT A.x + A.y AS z FROM A WHERE z = 10
-- z 在此處不可用卑吭,因?yàn)镾ELECT是最后執(zhí)行的語(yǔ)句芽淡!

如果你想重用別名z,你有兩個(gè)選擇豆赏。要么就重新寫(xiě)一遍 z 所代表的表達(dá)式:

SELECT A.x + A.y AS z FROM A WHERE (A.x + A.y) = 10
或者求助于衍生表挣菲、通用數(shù)據(jù)表達(dá)式或者視圖,以避免別名重用掷邦。
  1. 無(wú)論在語(yǔ)法上還是在執(zhí)行順序上白胀, UNION 總是排在在 ORDER BY 之前。很多人認(rèn)為每個(gè) UNION 段都能使用 ORDER BY 排序抚岗,但是根據(jù) SQL 語(yǔ)言標(biāo)準(zhǔn)和各個(gè)數(shù)據(jù)庫(kù) SQL的執(zhí)行差異來(lái)看或杠,這并不是真的。

  2. 盡管某些數(shù)據(jù)庫(kù)允許 SQL 語(yǔ)句對(duì)子查詢(xún)(subqueries)或者派生表(derived tables)進(jìn)行排序宣蔚,但是這并不說(shuō)明這個(gè)排序在 UNION 操作過(guò)后仍保持排序后的順序向抢。注意:并非所有的數(shù)據(jù)庫(kù)對(duì) SQL 語(yǔ)句使用相同的解析方式。如 MySQL胚委、PostgreSQL和 SQLite 中就不會(huì)按照上面第二點(diǎn)中所說(shuō)的方式執(zhí)行笋额。
    我們學(xué)到了什么?

既然并不是所有的數(shù)據(jù)庫(kù)都按照上述方式執(zhí)行 SQL篷扩,那我們的收獲是什么兄猩?

我們的收獲是永遠(yuǎn)要記得:SQL 語(yǔ)句的語(yǔ)法順序和其執(zhí)行順序并不一致,這樣我們就能避免一般性的錯(cuò)誤鉴未。如果你能記住 SQL 語(yǔ)句語(yǔ)法順序和執(zhí)行順序的差異枢冤,你就能很容易的理解一些很常見(jiàn)的 SQL 問(wèn)題。

當(dāng)然铜秆,如果一種語(yǔ)言被設(shè)計(jì)成語(yǔ)法順序直接反應(yīng)其語(yǔ)句的執(zhí)行順序淹真,那么這種語(yǔ)言對(duì)程序員是十分友好的,這種編程語(yǔ)言層面的設(shè)計(jì)理念已經(jīng)被微軟應(yīng)用到了 LINQ 語(yǔ)言中连茧。

3核蘸、SQL 語(yǔ)言的核心是對(duì)表的引用(table references)

由于 SQL 語(yǔ)句語(yǔ)法順序和執(zhí)行順序的不同,很多同學(xué)會(huì)認(rèn)為SELECT 中的字段信息是 SQL 語(yǔ)句的核心啸驯。其實(shí)真正的核心在于對(duì)表的引用客扎。

根據(jù) SQL 標(biāo)準(zhǔn),F(xiàn)ROM 語(yǔ)句被定義為:

<from clause> ::= FROM <table reference> [ { <comma> <table reference> }... ]

FROM語(yǔ)句的“輸出”是一張聯(lián)合表罚斗,來(lái)自于所有引用的表在某一維度上的聯(lián)合徙鱼。我們們慢慢來(lái)分析:

FROM a, b

上面這句 FROM 語(yǔ)句的輸出是一張聯(lián)合表,聯(lián)合了表 a 和表 b 。如果 a 表有三個(gè)字段袱吆, b 表有 5 個(gè)字段厌衙,那么這個(gè)“輸出表”就有 8 ( =5+3)個(gè)字段。

這個(gè)聯(lián)合表里的數(shù)據(jù)是 ab绞绒,即 a 和 b 的笛卡爾積婶希。換句話(huà)說(shuō),也就是 a 表中的每一條數(shù)據(jù)都要跟 b 表中的每一條數(shù)據(jù)配對(duì)蓬衡。如果 a 表有3 條數(shù)據(jù)饲趋, b 表有 5 條數(shù)據(jù),那么聯(lián)合表就會(huì)有 15 ( =53)條數(shù)據(jù)撤蟆。

FROM 輸出的結(jié)果被 WHERE 語(yǔ)句篩選后要經(jīng)過(guò) GROUP BY 語(yǔ)句處理,從而形成新的輸出結(jié)果堂污。

如果我們從集合論(關(guān)系代數(shù))的角度來(lái)看家肯,一張數(shù)據(jù)庫(kù)的表就是一組數(shù)據(jù)元的關(guān)系,而每個(gè) SQL 語(yǔ)句會(huì)改變一種或數(shù)種關(guān)系盟猖,從而產(chǎn)生出新的數(shù)據(jù)元的關(guān)系(即產(chǎn)生新的表)讨衣。

我們學(xué)到了什么?

思考問(wèn)題的時(shí)候從表的角度來(lái)思考問(wèn)題提式镐,這樣很容易理解數(shù)據(jù)如何在 SQL 語(yǔ)句的“流水線(xiàn)”上進(jìn)行了什么樣的變動(dòng)反镇。

4、靈活引用表能使 SQL 語(yǔ)句變得更強(qiáng)大

靈活引用表能使 SQL 語(yǔ)句變得更強(qiáng)大娘汞。一個(gè)簡(jiǎn)單的例子就是 JOIN 的使用歹茶。

嚴(yán)格的說(shuō) JOIN 語(yǔ)句并非是 SELECT 中的一部分,而是一種特殊的表引用語(yǔ)句你弦。

SQL 語(yǔ)言標(biāo)準(zhǔn)中表的連接定義如下:

<table reference> ::=
  <table name>
  | <derived table>
  | <joined table>

就拿之前的例子來(lái)說(shuō):

FROM a, b

a 可能輸如下表的連接:

a1 JOIN a2 ON a1.id = a2.id

將它放到之前的例子中就變成了:

盡管將一個(gè)連接表用逗號(hào)跟另一張表聯(lián)合在一起并不是常用作法惊豺,但是你的確可以這么做。結(jié)果就是禽作,最終輸出的表就有了 a1+a2+b 個(gè)字段了尸昧。

在 SQL 語(yǔ)句中派生表的應(yīng)用甚至比表連接更加強(qiáng)大,下面我們就要講到表連接旷偿。

我們學(xué)到了什么烹俗?

思考問(wèn)題時(shí),要從表引用的角度出發(fā)萍程,這樣就很容易理解數(shù)據(jù)是怎樣被 SQL 語(yǔ)句處理的幢妄,并且能夠幫助你理解那些復(fù)雜的表引用是做什么的。

更重要的是茫负,要理解 JOIN 是構(gòu)建連接表的關(guān)鍵詞磁浇,并不是 SELECT 語(yǔ)句的一部分。有一些數(shù)據(jù)庫(kù)允許在 INSERT 朽褪、 UPDATE 置吓、 DELETE 中使用 JOIN 无虚。

5、SQL 語(yǔ)句中推薦使用表連接

我們先看看剛剛這句話(huà):

FROM a, b

高級(jí) SQL 程序員也許給你忠告:盡量不要使用逗號(hào)來(lái)代替 JOIN 進(jìn)行表的連接衍锚,這樣會(huì)提高你的 SQL 語(yǔ)句的可讀性友题,并且可以避免一些錯(cuò)誤。利用逗號(hào)來(lái)簡(jiǎn)化 SQL 語(yǔ)句有時(shí)候會(huì)造成思維上的混亂戴质,想一下下面的語(yǔ)句:

FROM a, b, c, d, e, f, g, h
  WHERE a.a1 = b.bx
  AND a.a2 = c.c1
  AND d.d1 = b.bc
  -- etc...

我們不難看出使用 JOIN 語(yǔ)句的好處在于:安全度宦。JOIN 和要連接的表離得非常近,這樣就能避免錯(cuò)誤告匠。

更多連接的方式戈抄,JOIN 語(yǔ)句能去區(qū)分出來(lái)外連接和內(nèi)連接等。

我們學(xué)到了什么后专?

記著要盡量使用 JOIN 進(jìn)行表的連接划鸽,永遠(yuǎn)不要在 FROM 后面使用逗號(hào)連接表。

6戚哎、SQL 語(yǔ)句中不同的連接操作

SQL 語(yǔ)句中裸诽,表連接的方式從根本上分為五種:

EQUI JOIN
SEMI JOIN
ANTI JOIN
CROSS JOIN
DIVISION

EQUI JOIN 是一種最普通的 JOIN 操作,它包含兩種連接方式:

INNER JOIN(或者是 JOIN )

OUTER JOIN(包括:LEFT 型凳、 RIGHT丈冬、 FULL OUTER JOIN)

用例子最容易說(shuō)明其中區(qū)別:

-- This table reference contains authors and their books.
-- There is one record for each book and its author.
-- authors without books are NOT included
author JOIN book ON author.id = book.author_id

-- This table reference contains authors and their books
-- There is one record for each book and its author.
-- ... OR there is an "empty" record for authors without books-- ("empty" meaning that all book columns are NULL)

author LEFT OUTER JOIN book ON author.id = book.author_id
SEMI JOIN

這種連接關(guān)系在 SQL 中有兩種表現(xiàn)方式:使用 IN,或者使用 EXISTS甘畅」∪铮“ SEMI ”在拉丁文中是“半”的意思。這種連接方式是只連接目標(biāo)表的一部分疏唾。這是什么意思呢粒梦?

再想一下上面關(guān)于作者和書(shū)名的連接。我們想象一下這樣的情況:我們不需要作者 / 書(shū)名這樣的組合荸实,只是需要那些在書(shū)名表中的書(shū)的作者信息匀们。那我們就能這么寫(xiě):

-- Using IN
FROM author
WHERE author.id IN(SELECT book.author_id FROM book)
 

-- Using EXISTS
FROM author
WHERE EXISTS (SELECT 1 FROM book WHERE book.author_id = author.id)

盡管沒(méi)有嚴(yán)格的規(guī)定說(shuō)明你何時(shí)應(yīng)該使用 IN ,何時(shí)應(yīng)該使用 EXISTS 准给,但是這些事情你還是應(yīng)該知道的:

IN比 EXISTS 的可讀性更好
EXISTS 比IN 的表達(dá)性更好(更適合復(fù)雜的語(yǔ)句)
二者之間性能沒(méi)有差異(但對(duì)于某些數(shù)據(jù)庫(kù)來(lái)說(shuō)性能差異會(huì)非常大) 因?yàn)槭褂?INNER JOIN 也能得到書(shū)名表中書(shū)所對(duì)應(yīng)的作者信息泄朴,所以很多初學(xué)者機(jī)會(huì)認(rèn)為可以通過(guò) DISTINCT 進(jìn)行去重,然后將 SEMI JOIN 語(yǔ)句寫(xiě)成這樣:

-- Find only those authors who also have books
SELECT DISTINCT first_name, last_name
FROM author
JOIN book ON author.id = book.author_id

這是一種很糟糕的寫(xiě)法露氮,原因如下:
SQL 語(yǔ)句性能低下:因?yàn)槿ブ夭僮鳎?DISTINCT )需要數(shù)據(jù)庫(kù)重復(fù)從硬盤(pán)中讀取數(shù)據(jù)到內(nèi)存中祖灰。
這么寫(xiě)并非完全正確:盡管也許現(xiàn)在這么寫(xiě)不會(huì)出現(xiàn)問(wèn)題,但是隨著 SQL 語(yǔ)句變得越來(lái)越復(fù)雜畔规,你想要去重得到正確的結(jié)果就變得十分困難局扶。

ANTI JOIN

這種連接的關(guān)系跟 SEMI JOIN 剛好相反。在 IN 或者 EXISTS 前加一個(gè) NOT 關(guān)鍵字就能使用這種連接。舉個(gè)例子來(lái)說(shuō)三妈,我們列出書(shū)名表里沒(méi)有書(shū)的作者:

-- Using IN
FROM author
WHERE author.id NOT IN(SELECT book.author_id FROM book)

-- Using EXISTS
FROM author
WHERE NOT EXISTS (SELECT 1 FROM book WHEREbook.author_id = author.id)

關(guān)于性能畜埋、可讀性、表達(dá)性等特性也完全可以參考 SEMI JOIN畴蒲。

CROSS JOIN

這個(gè)連接過(guò)程就是兩個(gè)連接的表的乘積:即將第一張表的每一條數(shù)據(jù)分別對(duì)應(yīng)第二張表的每條數(shù)據(jù)悠鞍。我們之前見(jiàn)過(guò),這就是逗號(hào)在 FROM 語(yǔ)句中的用法模燥。在實(shí)際的應(yīng)用中咖祭,很少有地方能用到 CROSS JOIN,但是一旦用上了蔫骂,你就可以用這樣的 SQL語(yǔ)句表達(dá):

-- Combine every author with every bookauthor CROSS JOIN book

DIVISION DIVISION 的確是一個(gè)怪胎么翰。簡(jiǎn)而言之,如果 JOIN 是一個(gè)乘法運(yùn)算辽旋,那么 DIVISION 就是 JOIN 的逆過(guò)程浩嫌。DIVISION 的關(guān)系很難用 SQL 表達(dá)出來(lái),介于這是一個(gè)新手指南戴已,解釋 DIVISION 已經(jīng)超出了我們的目的。

我們學(xué)到了什么锅减?

學(xué)到了很多糖儡!讓我們?cè)谀X海中再回想一下。SQL 是對(duì)表的引用怔匣, JOIN 則是一種引用表的復(fù)雜方式握联。但是 SQL 語(yǔ)言的表達(dá)方式和實(shí)際我們所需要的邏輯關(guān)系之間是有區(qū)別的,并非所有的邏輯關(guān)系都能找到對(duì)應(yīng)的 JOIN 操作每瞒,所以這就要我們?cè)谄綍r(shí)多積累和學(xué)習(xí)關(guān)系邏輯金闽,這樣你就能在以后編寫(xiě) SQL 語(yǔ)句中選擇適當(dāng)?shù)?JOIN 操作了。

7剿骨、SQL 中如同變量的派生表

在這之前代芜,我們學(xué)習(xí)到過(guò) SQL 是一種聲明性的語(yǔ)言,并且 SQL 語(yǔ)句中不能包含變量浓利。但是你能寫(xiě)出類(lèi)似于變量的語(yǔ)句挤庇,這些就叫做派生表:

說(shuō)白了,所謂的派生表就是在括號(hào)之中的子查詢(xún):

-- A derived table
FROM (SELECT * FROM author)

需要注意的是有些時(shí)候我們可以給派生表定義一個(gè)相關(guān)名(即我們所說(shuō)的別名)贷掖。

-- A derived table with an alias
FROM(SELECT * FROM author) a

派生表可以有效的避免由于 SQL 邏輯而產(chǎn)生的問(wèn)題嫡秕。

舉例來(lái)說(shuō):如果你想重用一個(gè)用 SELECT 和 WHERE 語(yǔ)句查詢(xún)出的結(jié)果,這樣寫(xiě)就可以(以 Oracle 為例):

-- Get authors' first and last names, and their age in days
SELECT first_name, last_name, age
FROM(
 SELECT first_name, last_name, current_date- date_of_birth age
 FROM author
)
-- If the age is greater than 10000 days
WHEREage > 10000

需要我們注意的是:在有些數(shù)據(jù)庫(kù)苹威,以及 SQL :1990 標(biāo)準(zhǔn)中昆咽,派生表被歸為下一級(jí)——通用表語(yǔ)句( common table experssion)。這就允許你在一個(gè) SELECT 語(yǔ)句中對(duì)派生表多次重用。

上面的例子就(幾乎)等價(jià)于下面的語(yǔ)句:

WITH a AS(
 SELECT first_name, last_name, current_date- date_of_birth age
 FROM author
)
SELECT *
FROM a
WHERE age > 10000

當(dāng)然了掷酗,你也可以給“ a ”創(chuàng)建一個(gè)單獨(dú)的視圖调违,這樣你就可以在更廣泛的范圍內(nèi)重用這個(gè)派生表了。

我們學(xué)到了什么汇在?

我們反復(fù)強(qiáng)調(diào)翰萨,大體上來(lái)說(shuō) SQL 語(yǔ)句就是對(duì)表的引用,而并非對(duì)字段的引用糕殉。要好好利用這一點(diǎn)亩鬼,不要害怕使用派生表或者其他更復(fù)雜的語(yǔ)句。

8阿蝶、SQL 語(yǔ)句中 GROUP BY 是對(duì)表的引用進(jìn)行的操作

讓我們?cè)倩叵胍幌轮暗?FROM 語(yǔ)句:

FROM a, b

現(xiàn)在雳锋,我們將 GROUP BY 應(yīng)用到上面的語(yǔ)句中:

GROUP BY A.x, A.y, B.z

上面語(yǔ)句的結(jié)果就是產(chǎn)生出了一個(gè)包含三個(gè)字段的新的表的引用。我們來(lái)仔細(xì)理解一下這句話(huà):當(dāng)你應(yīng)用 GROUP BY 的時(shí)候羡洁, SELECT 后沒(méi)有使用聚合函數(shù)的列玷过,都要出現(xiàn)在 GROUP BY 后面。(譯者注:原文大意為“當(dāng)你是用 GROUP BY 的時(shí)候筑煮,你能夠?qū)ζ溥M(jìn)行下一級(jí)邏輯操作的列會(huì)減少辛蚊,包括在 SELECT 中的列”)。需要注意的是:其他字段能夠使用聚合函數(shù):

SELECT A.x, A.y, SUM(A.z)
FROM A
GROUP BY A.x, A.y

還有一點(diǎn)值得留意的是:MySQL 并不堅(jiān)持這個(gè)標(biāo)準(zhǔn)真仲,這的確是令人很困惑的地方袋马。(譯者注:這并不是說(shuō) MySQL 沒(méi)有 GROUP BY 的功能)但是不要被 MySQL 所迷惑。GROUP BY 改變了對(duì)表引用的方式秸应。你可以像這樣既在 SELECT 中引用某一字段虑凛,也在 GROUP BY 中對(duì)其進(jìn)行分組。

我們學(xué)到了什么软啼?

GROUP BY桑谍,再次強(qiáng)調(diào)一次,是在表的引用上進(jìn)行了操作祸挪,將其轉(zhuǎn)換為一種新的引用方式锣披。

9、SQL 語(yǔ)句中的 SELECT 實(shí)質(zhì)上是對(duì)關(guān)系的映射

我個(gè)人比較喜歡“映射”這個(gè)詞贿条,尤其是把它用在關(guān)系代數(shù)上盈罐。(譯者注:原文用詞為 projection ,該詞有兩層含義闪唆,第一種含義是預(yù)測(cè)盅粪、規(guī)劃、設(shè)計(jì)悄蕾,第二種意思是投射票顾、映射础浮,經(jīng)過(guò)反復(fù)推敲,我覺(jué)得這里用映射能夠更直觀(guān)的表達(dá)出 SELECT 的作用)奠骄。一旦你建立起來(lái)了表的引用豆同,經(jīng)過(guò)修改、變形含鳞,你能夠一步一步的將其映射到另一個(gè)模型中影锈。

SELECT 語(yǔ)句就像一個(gè)“投影儀”,我們可以將其理解成一個(gè)將源表中的數(shù)據(jù)按照一定的邏輯轉(zhuǎn)換成目標(biāo)表數(shù)據(jù)的函數(shù)蝉绷。

通過(guò)SELECT語(yǔ)句鸭廷,你能對(duì)每一個(gè)字段進(jìn)行操作,通過(guò)復(fù)雜的表達(dá)式生成所需要的數(shù)據(jù)熔吗。

SELECT 語(yǔ)句有很多特殊的規(guī)則辆床,至少你應(yīng)該熟悉以下幾條:

  1. 你僅能夠使用那些能通過(guò)表引用而得來(lái)的字段;
  2. 如果你有 GROUP BY 語(yǔ)句桅狠,你只能夠使用 GROUP BY 語(yǔ)句后面的字段或者聚合函數(shù)讼载;
  3. 當(dāng)你的語(yǔ)句中沒(méi)有 GROUP BY 的時(shí)候,可以使用開(kāi)窗函數(shù)代替聚合函數(shù)中跌;
  4. 當(dāng)你的語(yǔ)句中沒(méi)有 GROUP BY 的時(shí)候咨堤,你不能同時(shí)使用聚合函數(shù)和其它函數(shù);
  5. 有一些方法可以將普通函數(shù)封裝在聚合函數(shù)中漩符;
  6. ……

一些更復(fù)雜的規(guī)則多到足夠?qū)懗隽硪黄恼铝艘淮1热纾簽楹文悴荒茉谝粋€(gè)沒(méi)有 GROUP BY 的 SELECT 語(yǔ)句中同時(shí)使用普通函數(shù)和聚合函數(shù)?(上面的第 4 條)

原因如下:

憑直覺(jué)陨仅,這種做法從邏輯上就講不通津滞。如果直覺(jué)不能夠說(shuō)服你铝侵,那么語(yǔ)法肯定能灼伤。SQL : 1999 標(biāo)準(zhǔn)引入了 GROUPING SETS,SQL:2003 標(biāo)準(zhǔn)引入了 group sets : GROUP BY() 咪鲜。無(wú)論什么時(shí)候狐赡,只要你的語(yǔ)句中出現(xiàn)了聚合函數(shù),而且并沒(méi)有明確的 GROUP BY 語(yǔ)句疟丙,這時(shí)一個(gè)不明確的颖侄、空的 GROUPING SET 就會(huì)被應(yīng)用到這段 SQL 中。因此享郊,原始的邏輯順序的規(guī)則就被打破了览祖,映射(即 SELECT )關(guān)系首先會(huì)影響到邏輯關(guān)系,其次就是語(yǔ)法關(guān)系炊琉。(譯者注:這段話(huà)原文就比較艱澀展蒂,可以簡(jiǎn)單理解如下:在既有聚合函數(shù)又有普通函數(shù)的 SQL 語(yǔ)句中又活,如果沒(méi)有 GROUP BY 進(jìn)行分組,SQL 語(yǔ)句默認(rèn)視整張表為一個(gè)分組锰悼,當(dāng)聚合函數(shù)對(duì)某一字段進(jìn)行聚合統(tǒng)計(jì)的時(shí)候柳骄,引用的表中的每一條 record 就失去了意義,全部的數(shù)據(jù)都聚合為一個(gè)統(tǒng)計(jì)值箕般,你此時(shí)對(duì)每一條 record 使用其它函數(shù)是沒(méi)有意義的)耐薯。糊涂了?是的丝里,我也是曲初。我們?cè)倩剡^(guò)頭來(lái)看點(diǎn)淺顯的東西吧。

我們學(xué)到了什么丙者?

SELECT 語(yǔ)句可能是 SQL 語(yǔ)句中最難的部分了复斥,盡管他看上去很簡(jiǎn)單。其他語(yǔ)句的作用其實(shí)就是對(duì)表的不同形式的引用械媒。而 SELECT 語(yǔ)句則把這些引用整合在了一起目锭,通過(guò)邏輯規(guī)則將源表映射到目標(biāo)表,而且這個(gè)過(guò)程是可逆的纷捞,我們可以清楚的知道目標(biāo)表的數(shù)據(jù)是怎么來(lái)的痢虹。

想要學(xué)習(xí)好 SQL 語(yǔ)言,就要在使用 SELECT 語(yǔ)句之前弄懂其他的語(yǔ)句主儡,雖然 SELECT 是語(yǔ)法結(jié)構(gòu)中的第一個(gè)關(guān)鍵詞奖唯,但它應(yīng)該是我們最后一個(gè)掌握的。

10糜值、SQL 語(yǔ)句中的幾個(gè)簡(jiǎn)單的關(guān)鍵詞:DISTINCT 丰捷, UNION , ORDER BY 和 OFFSET

在學(xué)習(xí)完復(fù)雜的 SELECT 之后寂汇,我們?cè)賮?lái)看點(diǎn)簡(jiǎn)單的東西:

集合運(yùn)算( set operation):集合運(yùn)算主要操作在于集合上病往,事實(shí)上指的就是對(duì)表的一種操作。從概念上來(lái)說(shuō)骄瓣,他們很好理解:

  • DISTINCT 在映射之后對(duì)數(shù)據(jù)進(jìn)行去重
  • UNION 將兩個(gè)子查詢(xún)拼接起來(lái)并去重
  • UNION ALL 將兩個(gè)子查詢(xún)拼接起來(lái)但不去重
  • EXCEPT 將第二個(gè)字查詢(xún)中的結(jié)果從第一個(gè)子查詢(xún)中去掉
  • INTERSECT 保留兩個(gè)子查詢(xún)中都有的結(jié)果并去重

排序運(yùn)算( ordering operation):

排序運(yùn)算跟邏輯關(guān)系無(wú)關(guān)停巷。這是一個(gè) SQL 特有的功能。排序運(yùn)算不僅在 SQL 語(yǔ)句的最后榕栏,而且在 SQL 語(yǔ)句運(yùn)行的過(guò)程中也是最后執(zhí)行的畔勤。使用 ORDER BY 和 OFFSET…FETCH 是保證數(shù)據(jù)能夠按照順序排列的最有效的方式。其他所有的排序方式都有一定隨機(jī)性扒磁,盡管它們得到的排序結(jié)果是可重現(xiàn)的庆揪。OFFSET…SET是一個(gè)沒(méi)有統(tǒng)一確定語(yǔ)法的語(yǔ)句,不同的數(shù)據(jù)庫(kù)有不同的表達(dá)方式妨托,如 MySQL 和 PostgreSQL 的 LIMIT…OFFSET缸榛、SQL Server 和 Sybase 的 TOP…START AT 等检访。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仔掸,隨后出現(xiàn)的幾起案子脆贵,更是在濱河造成了極大的恐慌,老刑警劉巖起暮,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卖氨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡负懦,警方通過(guò)查閱死者的電腦和手機(jī)筒捺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)纸厉,“玉大人系吭,你說(shuō)我怎么就攤上這事】牌罚” “怎么了肯尺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)躯枢。 經(jīng)常有香客問(wèn)我则吟,道長(zhǎng),這世上最難降的妖魔是什么锄蹂? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任氓仲,我火速辦了婚禮,結(jié)果婚禮上得糜,老公的妹妹穿的比我還像新娘敬扛。我一直安慰自己,他們只是感情好朝抖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布啥箭。 她就那樣靜靜地躺著,像睡著了一般槽棍。 火紅的嫁衣襯著肌膚如雪捉蚤。 梳的紋絲不亂的頭發(fā)上抬驴,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天炼七,我揣著相機(jī)與錄音,去河邊找鬼布持。 笑死豌拙,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的题暖。 我是一名探鬼主播按傅,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼捉超,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了唯绍?” 一聲冷哼從身側(cè)響起拼岳,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎况芒,沒(méi)想到半個(gè)月后惜纸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绝骚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年耐版,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片压汪。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡粪牲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出止剖,到底是詐尸還是另有隱情腺阳,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布穿香,位于F島的核電站舌狗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏扔水。R本人自食惡果不足惜痛侍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望魔市。 院中可真熱鬧主届,春花似錦、人聲如沸待德。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)将宪。三九已至绘闷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間较坛,已是汗流浹背印蔗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丑勤,地道東北人华嘹。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像法竞,于是被迫代替她去往敵國(guó)和親耙厚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子强挫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 很多程序員視 SQL 為洪水猛獸俯渤。SQL 是一種為數(shù)不多的聲明性語(yǔ)言,它的運(yùn)行方式完全不同于我們所熟知的命令行語(yǔ)言...
    guanguans閱讀 860評(píng)論 0 26
  • 整理自網(wǎng)絡(luò),我也忘了從哪個(gè)網(wǎng)站了诡曙。 一臀叙、SQL是一種聲明式語(yǔ)言 首先要把這個(gè)概念記在腦中:“聲明”。 SQL 語(yǔ)言...
    liycode閱讀 1,413評(píng)論 1 11
  • 摘自【十步完全理解 SQL】 很多程序員視 SQL 為洪水猛獸价卤。SQL 是一種為數(shù)不多的聲明性語(yǔ)言劝萤,它的運(yùn)行方式完...
    BigbyLong閱讀 1,702評(píng)論 0 51
  • 超經(jīng)典床嫌!十步完全理解 SQL 很多程序員視 SQL 為洪水猛獸。SQL 是一種為數(shù)不多的聲明性語(yǔ)言胸私,它的運(yùn)行方式完...
    iamChel閱讀 182評(píng)論 0 0
  • 久違的晴天厌处,家長(zhǎng)會(huì)。 家長(zhǎng)大會(huì)開(kāi)好到教室時(shí)岁疼,離放學(xué)已經(jīng)沒(méi)多少時(shí)間了阔涉。班主任說(shuō)已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評(píng)論 16 22