您當前的位置:首頁 > 農業

sql入門第一步(3)

作者:由 傳說中的黑本子 發表于 農業時間:2022-02-16

本筆記為阿里雲天池龍珠計劃SQL訓練營的學習內容,連結為:https://tianchi。aliyun。com/specials/promotion/aicampsql;

sql入門第一步:

https://

zhuanlan。zhihu。com/p/46

3499405

sql入門第一步(2):

https://

zhuanlan。zhihu。com/p/46

4160257

一、 檢視

我們先來看一個查詢語句(僅做示例,未提供相關資料)

SELECT stu_name FROM view_students_info;

單從表面上看起來這個語句是和正常的從資料表中查詢資料是完全相同的,但其實我們操作的是一個檢視。所以從SQL的角度來說操作檢視與操作表看起來是完全相同的,那麼為什麼還會有檢視的存在呢?檢視到底是什麼?檢視與表有什麼不同呢?

1.1 什麼是檢視

檢視是一個虛擬的表,不同於直接操作資料表,檢視是依據SELECT語句來建立的(會在下面具體介紹),所以操作檢視時會根據建立檢視的SELECT語句生成一張虛擬表,然後在這張虛擬表上做SQL操作。

1.2 檢視與表有什麼區別

sql

基礎

教程**第2版

》用一句話非常凝練的概括了檢視與表的區別—

“是否儲存了實際的資料”

。所以檢視並不是資料庫真實儲存的資料表,它可以看作是一個視窗,透過這個視窗我們可以看到資料庫表中真實存在的資料。所以我們要區別檢視和資料表的本質,即檢視是基於真實表的一張虛擬的表,其資料來源均建立在真實表的基礎上。

sql入門第一步(3)

圖片來源:《sql基礎教程第2版》

下面這句順口溜也方便大家記憶檢視與表的關係:“檢視不是表,檢視是虛表,檢視依賴於表”。

1.3 為什麼會存在檢視

那既然已經有資料表了,為什麼還需要檢視呢?主要有以下幾點原因:

透過定義檢視可以將頻繁使用的SELECT語句儲存以提高效率。

透過定義檢視可以使使用者看到的資料更加清晰。

透過定義檢視可以不對外公開資料表全部欄位,增強資料的保密性。

透過定義檢視可以降低資料的冗餘。

1.4 如何建立檢視

說了這麼多檢視與表的區別,下面我們就一起來看一下如何建立檢視吧。

建立檢視的基本語法如下:

CREATE VIEW <檢視名稱>(<列名1>,<列名2>,。。。) AS

其中SELECT 語句需要書寫在 AS 關鍵字之後。 SELECT 語句中列的排列順序和檢視中列的排列順序相同, SELECT 語句中的第 1 列就是檢視中的第 1 列, SELECT 語句中的第 2 列就是檢視中的第 2 列,以此類推。而且檢視的列名是在檢視名稱之後的列表中定義的。

需要注意的是檢視名在資料庫中需要是唯一的,不能與其他檢視和表重名。

檢視不僅可以基於真實表,我們也可以在檢視的基礎上繼續建立檢視。

sql入門第一步(3)

圖片來源:《sql基礎教程第2版》

雖然在檢視上繼續建立檢視的語法沒有錯誤,但是我們還是應該儘量避免這種操作。這是因為對多數 DBMS 來說, 多重檢視會降低 SQL 的效能。

注意事項

需要注意的是在一般的DBMS中定義檢視時不能使用ORDER BY語句。下面這樣定義檢視是錯誤的。

CREATE VIEW productsum (product_type, cnt_product)

AS

SELECT product_type, COUNT(*)

FROM product

GROUP BY product_type

ORDER BY product_type;

為什麼不能使用 ORDER BY 子句呢?這是因為檢視和表一樣,

資料行都是沒有順序的

在 MySQL中檢視的定義是允許使用 ORDER BY 語句的,但是若從特定檢視進行選擇,而該檢視使用了自己的 ORDER BY 語句,則檢視定義中的 ORDER BY 將被忽略。

基於單表的檢視

我們在product表的基礎上建立一個檢視,如下:

CREATE VIEW productsum (product_type, cnt_product)

AS

SELECT product_type, COUNT(*)

FROM product

GROUP BY product_type ;

建立的檢視如下圖所示(檢視時用SELECT * FROM productsum即可):

sql入門第一步(3)

基於多表的檢視

為了學習多表檢視,我們再建立一張表,相關程式碼如下:

CREATE TABLE shop_product

(shop_id CHAR(4) NOT NULL,

shop_name VARCHAR(200) NOT NULL,

product_id CHAR(4) NOT NULL,

quantity INTEGER NOT NULL,

PRIMARY KEY (shop_id, product_id));

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000A’, ‘東京’, ‘0001’, 30);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000A’, ‘東京’, ‘0002’, 50);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000A’, ‘東京’, ‘0003’, 15);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0002’, 30);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0003’, 120);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0004’, 20);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0006’, 10);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0007’, 40);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000C’, ‘大阪’, ‘0003’, 20);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000C’, ‘大阪’, ‘0004’, 50);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000C’, ‘大阪’, ‘0006’, 90);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000C’, ‘大阪’, ‘0007’, 70);

INSERT INTO shop_product (shop_id, shop_name, product_id, quantity) VALUES (‘000D’, ‘福岡’, ‘0001’, 100);

我們在product表和shop_product表的基礎上建立檢視。

CREATE VIEW view_shop_product(product_type, sale_price, shop_name)

AS

SELECT product_type, sale_price, shop_name

FROM product,

shop_product

WHERE product。product_id = shop_product。product_id;

建立的檢視如下圖所示

sql入門第一步(3)

我們可以在這個檢視的基礎上進行查詢

SELECT sale_price, shop_name

FROM view_shop_product

WHERE product_type = ‘衣服’;

查詢結果為:

sql入門第一步(3)

1.5 如何修改檢視結構

修改檢視結構的基本語法如下:

ALTER VIEW <檢視名> AS

其中檢視名在資料庫中需要是唯一的,不能與其他檢視和表重名。

當然也可以透過將當前檢視刪除然後重新建立的方式達到修改的效果。(對於資料庫底層是不是也是這樣操作的呢,你可以自己探索一下。)

修改檢視

我們修改上方的productSum檢視為

ALTER VIEW productSum

AS

SELECT product_type, sale_price

FROM Product

WHERE regist_date > ‘2009-09-11’;

此時productSum檢視內容如下圖所示

sql入門第一步(3)

1.6 如何更新檢視內容

因為檢視是一個虛擬表,所以對檢視的操作就是對底層基礎表的操作,所以在修改時只有滿足底層基本表的定義才能成功修改。

對於一個檢視來說,如果包含以下結構的任意一種都是不可以被更新的:

聚合函式 SUM()、MIN()、MAX()、COUNT() 等。

DISTINCT 關鍵字。

GROUP BY 子句。

HAVING 子句。

UNION 或 UNION ALL 運算子。

FROM 子句中包含多個表。

檢視歸根結底還是從表派生出來的,因此,如果原表可以更新,那麼 檢視中的資料也可以更新。反之亦然,如果檢視發生了改變,而原表沒有進行相應更新的話,就無法保證資料的一致性了。

更新檢視

因為我們剛剛修改的productSum檢視不包括以上的限制條件,我們來嘗試更新一下檢視

UPDATE productsum

SET sale_price = ‘5000’

WHERE product_type = ‘辦公用品’;

此時我們再檢視productSum檢視,可以發現數據已經更新了

sql入門第一步(3)

此時觀察原表也可以發現數據也被更新了

sql入門第一步(3)

不知道大家看到這個結果會不會有疑問,剛才修改檢視的時候是設定product_type=‘辦公用品’的商品的sale_price=5000,為什麼原表的資料只有一條做了修改呢?(這裡有一個問題,透過檢視修改後不知道會改變原表中的哪一條。)

還是因為檢視的定義,檢視只是原表的一個視窗,所以它修改也只能修改透過視窗能看到的內容。

注意:這裡雖然修改成功了,但是並不推薦這種使用方式。而且我們在建立檢視時也儘量使用限制不允許透過檢視來修改表

1.7 如何刪除檢視

刪除檢視的基本語法如下:

DROP VIEW <檢視名1> [ , <檢視名2> …]

注意:需要有相應的許可權才能成功刪除。

刪除檢視

我們刪除剛才建立的productSum檢視

DROP VIEW productSum;

如果我們繼續操作這個檢視的話就會提示當前操作的內容不存在。

二、 子查詢

我們先來看一個語句(僅做示例,未提供相關資料)

SELECT stu_name

FROM (

SELECT stu_name, COUNT(*) AS stu_cnt

FROM students_info

GROUP BY stu_age) AS studentSum;

這個語句看起來很好理解,其中使用括號括起來的sql語句首先執行,執行成功後再執行外面的sql語句。但是我們上一節提到的檢視也是根據SELECT語句建立檢視然後在這個基礎上再進行查詢。那麼什麼是子查詢呢?子查詢和檢視又有什麼關係呢?

2.1 什麼是子查詢

子查詢指一個查詢語句巢狀在另一個查詢語句內部的查詢,這個特性從 MySQL 4。1 開始引入,在 SELECT 子句中先計算子查詢,子查詢結果作為外層另一個查詢的過濾條件,查詢可以基於一個表或者多個表。

2.2 子查詢和檢視的關係

子查詢就是將用來定義檢視的 SELECT 語句直接用於 FROM 子句當中。其中AS studentSum可以看作是子查詢的名稱,而且由於子查詢是一次性的,所以子查詢不會像檢視那樣儲存在儲存介質中, 而是在 SELECT 語句

執行之後就消失

了。

2.3 巢狀子查詢

與在檢視上再定義檢視類似,子查詢也沒有具體的限制,例如我們可以這樣

SELECT product_type, cnt_product

FROM (SELECT *

FROM (SELECT product_type,

COUNT(*) AS cnt_product

FROM product

GROUP BY product_type) AS productsum

WHERE cnt_product = 4) AS productsum2;

其中最內層的子查詢我們將其命名為productSum,這條語句根據product_type分組並查詢個數,第二層查詢中將個數為4的商品查詢出來,最外層查詢product_type和cnt_product兩列。

雖然巢狀子查詢可以查詢出結果,但是隨著子查詢巢狀的層數的疊加,SQL語句不僅會難以理解而且執行效率也會很差,所以要儘量避免這樣的使用。

2.4 標量子查詢

標量就是單一的意思,那麼標量子查詢也就是單一的子查詢,那什麼叫做單一的子查詢呢?

所謂單一就是要求我們執行的SQL語句只能返回一個值,也就是要返回表中具體的

某一行的某一列

。例如我們有下面這樣一張表

product_id | product_name | sale_price

——————+——————-+——————

0003 | 運動T恤 | 4000

0004 | 菜刀 | 3000

0005 | 高壓鍋 | 6800

那麼我們執行一次標量子查詢後是要返回類似於,“0004”,“菜刀”這樣的結果。

2.5 標量子查詢有什麼用

我們現在已經知道標量子查詢可以返回一個值了,那麼它有什麼作用呢?

直接這樣想可能會有些困難,讓我們看幾個具體的需求:

查詢出銷售單價高於平均銷售單價的商品

查詢出注冊日期最晚的那個商品

你有思路了嗎?

讓我們看如何透過標量子查詢語句查詢出銷售單價高於平均銷售單價的商品。(sql入門第一步(2)中提過whe re後面不能接聚合函式)

SELECT product_id, product_name, sale_price

FROM product

WHERE sale_price > (SELECT AVG(sale_price) FROM product);

上面的這條語句首先後半部分查詢出product表中的平均售價,前面的sql語句在根據WHERE條件挑選出合適的商品。

由於標量子查詢的特性,導致標量子查詢不僅僅侷限於 WHERE 子句中,通常任何可以使用單一值的位置都可以使用。也就是說, 能夠使用常數或者列名的地方,無論是 SELECT 子句、GROUP BY 子句、HAVING 子句,還是 ORDER BY 子句,幾乎所有的地方都可以使用。

我們還可以這樣使用標量子查詢:

SELECT product_id,

product_name,

sale_price,

(SELECT AVG(sale_price)

FROM product) AS avg_price

FROM product;

你能猜到這段程式碼的執行結果是什麼嗎?執行一下看看與你想象的結果是否一致。

2.6 關聯子查詢

什麼是關聯子查詢

關聯子查詢既然包含關聯兩個字那麼一定意味著查詢與子查詢之間存在著聯絡。這種聯絡是如何建立起來的呢?

我們先看一個例子:

SELECT product_type, product_name, sale_price

FROM product AS p1

WHERE sale_price > (SELECT AVG(sale_price)

FROM product AS p2

WHERE p1。product_type = p2。product_type

GROUP BY product_type);

你能理解這個例子在做什麼操作麼?先來看一下這個例子的執行結果

sql入門第一步(3)

透過上面的例子我們大概可以猜到嗎,關聯子查詢就是透過一些標誌將內外兩層的查詢連線起來起到過濾資料的目的,接下來我們就一起看一下關聯子查詢的具體內容吧。

關聯子查詢與子查詢的聯絡

還記得我們之前的那個例子麼

查詢出銷售單價高於平均銷售單價的商品

,這個例子的SQL語句如下

SELECT product_id, product_name, sale_price

FROM product

WHERE sale_price > (SELECT AVG(sale_price) FROM product);

我們再來看一下這個需求

選取出各商品種類中高於該商品種類的平均銷售單價的商品

。SQL語句如下:

SELECT product_type, product_name, sale_price

FROM product ASp1

WHERE sale_price > (SELECT AVG(sale_price)

FROM product ASp2

WHERE p1。product_type =p2。product_type

GROUP BY product_type);

可以看出上面這兩個語句的區別嗎?

在第二條SQL語句也就是關聯子查詢中我們將外面的product表標記為p1,將內部的product設定為p2,而且透過WHERE語句連線了兩個查詢。

但是如果剛接觸的話一定會比較疑惑關聯查詢的執行過程,這裡有一個部落格講的比較清楚。在這裡我們簡要的概括為:

首先執行不帶WHERE的主查詢

根據主查詢訊結果匹配product_type,獲取子查詢結果

將子查詢結果再與主查詢結合執行完整的SQL語句

在子查詢中像標量子查詢,巢狀子查詢或者關聯子查詢可以看作是子查詢的一種操作方式即可。

小結

檢視和子查詢是資料庫操作中較為基礎的內容,對於一些複雜的查詢需要使用子查詢加一些條件語句組合才能得到正確的結果。但是無論如何對於一個SQL語句來說都不應該設計的層數非常深且特別複雜,不僅可讀性差而且執行效率也難以保證,所以儘量有簡潔的語句來完成需要的功能。

三、 函式

sql自帶了各種各樣的函式,極大提高了sql語言的便利性。

所謂函式,類似一個黑盒子,你給它一個輸入值,它便按照預設的程式定義給出返回值,輸入值稱為

引數

函式大致分為如下幾類:

算術函式 (用來進行數值計算的函式)

字串函式 (用來進行字串操作的函式)

日期函式 (用來進行日期操作的函式)

轉換函式 (用來轉換資料型別和值的函式)

聚合函式 (用來進行資料聚合的函式)

函式總個數超過200個,不需完全記住,常用函式有 30~50 個,其他不常用的函式使用時查閱文件即可。

3.1 算數函式

+ - * /

四則運算在之前的章節介紹過,此處不再贅述。

為了演示其他的幾個算數函式,在此構造

samplemath

—— DDL :建立表

USE shop;

DROP TABLE IF EXISTS samplemath;

CREATE TABLE samplemath

(m float(10,3),

n INT,

p INT);

—— DML :插入資料

START TRANSACTION; —— 開始事務

INSERT INTO samplemath(m, n, p) VALUES (500, 0, NULL);

INSERT INTO samplemath(m, n, p) VALUES (-180, 0, NULL);

INSERT INTO samplemath(m, n, p) VALUES (NULL, NULL, NULL);

INSERT INTO samplemath(m, n, p) VALUES (NULL, 7, 3);

INSERT INTO samplemath(m, n, p) VALUES (NULL, 5, 2);

INSERT INTO samplemath(m, n, p) VALUES (NULL, 4, NULL);

INSERT INTO samplemath(m, n, p) VALUES (8, NULL, 3);

INSERT INTO samplemath(m, n, p) VALUES (2。27, 1, NULL);

INSERT INTO samplemath(m, n, p) VALUES (5。555,2, NULL);

INSERT INTO samplemath(m, n, p) VALUES (NULL, 1, NULL);

INSERT INTO samplemath(m, n, p) VALUES (8。76, NULL, NULL);

COMMIT; —— 提交事務

—— 查詢表內容

SELECT * FROM samplemath;

ABS – 絕對值

語法:

ABS( 數值 )

ABS 函式用於計算一個數字的絕對值,表示一個數到原點的距離。

當 ABS 函式的引數為

NULL

時,返回值也是

NULL

MOD – 求餘數

語法:

MOD( 被除數,除數 )

MOD 是計算除法餘數(求餘)的函式,是 modulo 的縮寫。小數沒有餘數的概念,只能對整數列求餘數。

注意:主流的 DBMS 都支援 MOD 函式,只有SQL Server 不支援該函式,其使用

%

符號來計算餘數。

ROUND – 四捨五入

語法:

ROUND( 物件數值,保留小數的位數 )

ROUND 函式用來進行四捨五入操作。

注意:當引數

保留小數的位數

為變數時,可能會遇到錯誤,請謹慎使用變數。

SELECT m, ABS(m) AS abs_col , n, p, MOD(n, p) AS mod_col, ROUND(m,1) AS round_colS

FROM samplemath;

+——————+————-+————+————+————-+——————-+

| m | abs_col | n | p | mod_col | round_col |

+——————+————-+————+————+————-+——————-+

| 500。000 | 500。000 | 0 | NULL | NULL | 500。0 |

| -180。000 | 180。000 | 0 | NULL | NULL | -180。0 |

| NULL | NULL | NULL | NULL | NULL | NULL |

| NULL | NULL | 7 | 3 | 1 | NULL |

| NULL | NULL | 5 | 2 | 1 | NULL |

| NULL | NULL | 4 | NULL | NULL | NULL |

| 8。000 | 8。000 | NULL | 3 | NULL | 8。0 |

| 2。270 | 2。270 | 1 | NULL | NULL | 2。3 |

| 5。555 | 5。555 | 2 | NULL | NULL | 5。6 |

| NULL | NULL | 1 | NULL | NULL | NULL |

| 8。760 | 8。760 | NULL | NULL | NULL | 8。8 |

+——————+————-+————+————+————-+——————-+

11 rows in set (0。08 sec)

3.2 字串函式

字串函式也經常被使用,為了學習字串函式,在此我們構造

samplestr

表。

—— DDL :建立表

USE shop;

DROP TABLE IF EXISTS samplestr;

CREATE TABLE samplestr

(str1 VARCHAR (40),

str2 VARCHAR (40),

str3 VARCHAR (40)

);

—— DML:插入資料

START TRANSACTION;

INSERT INTO samplestr (str1, str2, str3) VALUES (‘opx’, ‘rt’, NULL);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘abc’, ‘def’, NULL);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘太陽’, ‘月亮’, ‘火星’);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘aaa’, NULL, NULL);

INSERT INTO samplestr (str1, str2, str3) VALUES (NULL, ‘xyz’, NULL);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘@!#$%’, NULL, NULL);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘ABC’, NULL, NULL);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘aBC’, NULL, NULL);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘abc哈哈’, ‘abc’, ‘ABC’);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘abcdefabc’, ‘abc’, ‘ABC’);

INSERT INTO samplestr (str1, str2, str3) VALUES (‘micmic’, ‘i’, ‘I’);

COMMIT;

—— 確認表中的內容

SELECT * FROM samplestr;

CONCAT – 拼接

語法:

CONCAT(str1, str2, str3)

MySQL中使用 CONCAT 函式進行拼接。

LENGTH – 字串長度

語法:

LENGTH( 字串 )

LOWER – 小寫轉換

LOWER 函式只能針對英文字母使用,它會將引數中的字串全都轉換為小寫。該函式不適用於英文字母以外的場合,不影響原本就是小寫的字元。

類似的, UPPER 函式用於大寫轉換。

REPLACE – 字串的替換

語法:

REPLACE( 物件字串,替換前的字串,替換後的字串 )

SUBSTRING – 字串的擷取

語法:

SUBSTRING (物件字串 FROM 擷取的起始位置 FOR 擷取的字元數)

使用 SUBSTRING 函式 可以截取出字串中的一部分字串。擷取的起始位置從字串最左側開始計算,索引值起始為1。

sql入門第一步(3)

(擴充套件內容)SUBSTRING_INDEX – 字串按索引擷取

語法:

SUBSTRING_INDEX (原始字串, 分隔符,n)

該函式用來獲取原始字串按照分隔符分割後,第 n 個分隔符之前(或之後)的子字串,支援正向和反向索引,索引起始值分別為 1 和 -1。

SELECT SUBSTRING_INDEX(‘www。mysql。com’, ‘。’, 2);

+——————————————————————+

| SUBSTRING_INDEX(‘www。mysql。com’, ‘。’, 2) |

+——————————————————————+

| www。mysql |

+——————————————————————+

1 row in set (0。00 sec)

SELECT SUBSTRING_INDEX(‘www。mysql。com’, ‘。’, -2);

+——————————————————————-+

| SUBSTRING_INDEX(‘www。mysql。com’, ‘。’, -2) |

+——————————————————————-+

| mysql。com |

+——————————————————————-+

1 row in set (0。00 sec)

獲取第1個元素比較容易,獲取第2個元素/第n個元素可以採用二次拆分的寫法。

SELECT SUBSTRING_INDEX(‘www。mysql。com’, ‘。’, 1);

+——————————————————————+

| SUBSTRING_INDEX(‘www。mysql。com’, ‘。’, 1) |

+——————————————————————+

| www |

+——————————————————————+

1 row in set (0。00 sec)

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(‘www。mysql。com’, ‘。’, 2), ‘。’, -1);

+——————————————————————————————————+

| SUBSTRING_INDEX(SUBSTRING_INDEX(‘www。mysql。com’, ‘。’, 2), ‘。’, -1) |

+——————————————————————————————————+

| mysql |

+——————————————————————————————————+

1 row in set (0。00 sec)

3.3 日期函式

不同DBMS的日期函式語法各有不同,本課程介紹一些被標準 SQL 承認的可以應用於絕大多數 DBMS 的函式。特定DBMS的日期函式查閱文件即可。

CURRENT_DATE – 獲取當前日期

SELECT CURRENT_DATE;

+————————+

| CURRENT_DATE |

+————————+

| 2020-08-08 |

+————————+

1 row in set (0。00 sec)

CURRENT_TIME – 當前時間

SELECT CURRENT_TIME;

+————————+

| CURRENT_TIME |

+————————+

| 17:26:09 |

+————————+

1 row in set (0。00 sec)

CURRENT_TIMESTAMP – 當前日期和時間

SELECT CURRENT_TIMESTAMP;

+——————————-+

| CURRENT_TIMESTAMP |

+——————————-+

| 2020-08-08 17:27:07 |

+——————————-+

1 row in set (0。00 sec)

EXTRACT – 擷取日期元素

語法:

EXTRACT(日期元素 FROM 日期)

使用 EXTRACT 函式可以截取出日期資料中的一部分,例如“年”

“月”,或者“小時”“秒”等。該函式的返回值並不是日期型別而是數值型別

SELECT CURRENT_TIMESTAMP as now,

EXTRACT(YEAR FROM CURRENT_TIMESTAMP) AS year,

EXTRACT(MONTH FROM CURRENT_TIMESTAMP) AS month,

EXTRACT(DAY FROM CURRENT_TIMESTAMP) AS day,

EXTRACT(HOUR FROM CURRENT_TIMESTAMP) AS hour,

EXTRACT(MINUTE FROM CURRENT_TIMESTAMP) AS MINute,

EXTRACT(SECOND FROM CURRENT_TIMESTAMP) AS second;

+——————————-+————+————-+————+————+————+————+

| now | year | month | day | hour | MINute | second |

+——————————-+————+————-+————+————+————+————+

| 2020-08-08 17:34:38 | 2020 | 8 | 8 | 17 | 34 | 38 |

+——————————-+————+————-+————+————+————+————+

1 row in set (0。00 sec)

3.4 轉換函式

“轉換”這個詞的含義非常廣泛,在 SQL 中主要有兩層意思:一是資料型別的轉換,簡稱為型別轉換,在英語中稱為

cast

;另一層意思是值的轉換。

CAST – 型別轉換

語法:

CAST(轉換前的值 AS 想要轉換的資料型別)

—— 將字串型別轉換為數值型別

SELECT CAST(‘0001’ AS SIGNED INTEGER) AS int_col;

+————-+

| int_col |

+————-+

| 1 |

+————-+

1 row in set (0。00 sec)

—— 將字串型別轉換為日期型別

SELECT CAST(‘2009-12-14’ AS DATE) AS date_col;

+——————+

| date_col |

+——————+

| 2009-12-14 |

+——————+

1 row in set (0。00 sec)

COALESCE – 將NULL轉換為其他值

語法:

COALESCE(資料1,資料2,資料3……)

COALESCE 是 SQL 特有的函式。該函式會返回可變引數 A 中左側開始第 1個不是NULL的值。引數個數是可變的,因此可以根據需要無限增加。

在 SQL 語句中將 NULL 轉換為其他值時就會用到轉換函式。

SELECT COALESCE(NULL, 11) AS col_1,

COALESCE(NULL, ‘hello world’, NULL) AS col_2,

COALESCE(NULL, NULL, ‘2020-11-01’) AS col_3;

+————-+——————-+——————+

| col_1 | col_2 | col_3 |

+————-+——————-+——————+

| 11 | hello world | 2020-11-01 |

+————-+——————-+——————+

1 row in set (0。00 sec)

3.5 謂詞

3.5.1 什麼是謂詞

謂詞就是返回值為真值的函式。包括

TRUE / FALSE / UNKNOWN

謂詞主要有以下幾個:

LIKE

BETWEEN

IS NULL、IS NOT NULL

IN

EXISTS

3.5.2 LIKE謂詞 – 用於字串的部分一致查詢

當需要進行字串的部分一致查詢時需要使用該謂詞。(%表示未知的字元,_表示未知的一個字元)

部分一致大體可以分為前方一致、中間一致和後方一致三種類型。

首先我們來建立一張表

—— DDL :建立表

CREATE TABLE samplelike

( strcol VARCHAR(6) NOT NULL,

PRIMARY KEY (strcol));

—— DML :插入資料

START TRANSACTION; —— 開始事務

INSERT INTO samplelike (strcol) VALUES (‘abcddd’);

INSERT INTO samplelike (strcol) VALUES (‘dddabc’);

INSERT INTO samplelike (strcol) VALUES (‘abdddc’);

INSERT INTO samplelike (strcol) VALUES (‘abcdd’);

INSERT INTO samplelike (strcol) VALUES (‘ddabc’);

INSERT INTO samplelike (strcol) VALUES (‘abddc’);

COMMIT; —— 提交事務

SELECT * FROM samplelike;

+————+

| strcol |

+————+

| abcdd |

| abcddd |

| abddc |

| abdddc |

| ddabc |

| dddabc |

+————+

6 rows in set (0。00 sec)

前方一致:選取出“dddabc”

前方一致即作為查詢條件的字串(這裡是“ddd”)與查詢物件字串起始部分相同。

SELECT *

FROM samplelike

WHERE strcol LIKE ‘ddd%’;

+————+

| strcol |

+————+

| dddabc |

+————+

1 row in set (0。00 sec)

其中的

%

是代表“零個或多個任意字串”的特殊符號,本例中代表“以ddd開頭的所有字串”。

中間一致:選取出“abcddd”,“dddabc”,“abdddc”

中間一致即查詢物件字串中含有作為查詢條件的字串,無論該字串出現在物件字

符串的最後還是中間都沒有關係。

SELECT *

FROM samplelike

WHERE strcol LIKE ‘%ddd%’;

+————+

| strcol |

+————+

| abcddd |

| abdddc |

| dddabc |

+————+

3 rows in set (0。00 sec)

後方一致:選取出“abcddd“

後方一致即作為查詢條件的字串(這裡是“ddd”)與查詢物件字串的末尾部分相同。

SELECT *

FROM samplelike

WHERE strcol LIKE ‘%ddd’;

+————+

| strcol |

+————+

| abcddd |

+————+

1 row in set (0。00 sec)

綜合如上三種類型的查詢可以看出,查詢條件最寬鬆,也就是能夠取得最多記錄的是

中間一致

。這是因為它同時包含前方一致和後方一致的查詢結果。

_

下劃線匹配任意 1 個字元

使用 _(下劃線)來代替 %,與 % 不同的是,它代表了“任意 1 個字元”。

SELECT *

FROM samplelike

WHERE strcol LIKE ‘abc__’;

+————+

| strcol |

+————+

| abcdd |

+————+

1 row in set (0。00 sec)

3.5.3 BETWEEN謂詞 – 用於範圍查詢

使用 BETWEEN 可以進行範圍查詢。該謂詞與其他謂詞或者函式的不同之處在於它使用了 3 個引數。

—— 選取銷售單價為100~ 1000元的商品

SELECT product_name, sale_price

FROM product

WHERE sale_price BETWEEN 100 AND 1000;

+————————+——————+

| product_name | sale_price |

+————————+——————+

| T恤 | 1000 |

| 打孔器 | 500 |

| 叉子 | 500 |

| 擦菜板 | 880 |

| 圓珠筆 | 100 |

+————————+——————+

5 rows in set (0。00 sec)

BETWEEN 的特點就是結果中會包含 100 和 1000 這兩個臨界值,也就是

閉區間

。如果不想讓結果中包含臨界值,那就必須使用 < 和 >。

SELECT product_name, sale_price

FROM product

WHERE sale_price > 100

AND sale_price < 1000;

+————————+——————+

| product_name | sale_price |

+————————+——————+

| 打孔器 | 500 |

| 叉子 | 500 |

| 擦菜板 | 880 |

+————————+——————+

3 rows in set (0。00 sec)

3.5.4 IS NULL、 IS NOT NULL – 用於判斷是否為NULL

為了選取出某些值為 NULL 的列的資料,不能使用 =,而只能使用特定的謂詞IS NULL。

SELECT product_name, purchase_price

FROM product

WHERE purchase_price IS NULL;

+————————+————————+

| product_name | purchase_price |

+————————+————————+

| 叉子 | NULL |

| 圓珠筆 | NULL |

+————————+————————+

2 rows in set (0。00 sec)

與此相反,想要選取 NULL 以外的資料時,需要使用IS NOT NULL。

SELECT product_name, purchase_price

FROM product

WHERE purchase_price IS NOT NULL;

+————————+————————+

| product_name | purchase_price |

+————————+————————+

| T恤 | 500 |

| 打孔器 | 320 |

| 運動T恤 | 2800 |

| 菜刀 | 2800 |

| 高壓鍋 | 5000 |

| 擦菜板 | 790 |

+————————+————————+

6 rows in set (0。00 sec)

3.5.5 IN謂詞 – OR的簡便用法

多個查詢條件取並集時可以選擇使用

or

語句。

—— 透過OR指定多個進貨單價進行查詢

SELECT product_name, purchase_price

FROM product

WHERE purchase_price = 320

OR purchase_price = 500

OR purchase_price = 5000;

+————————+————————+

| product_name | purchase_price |

+————————+————————+

| T恤 | 500 |

| 打孔器 | 320 |

| 高壓鍋 | 5000 |

+————————+————————+

3 rows in set (0。00 sec)

雖然上述方法沒有問題,但還是存在一點不足之處,那就是隨著希望選取的物件越來越多, SQL 語句也會越來越長,閱讀起來也會越來越困難。這時, 我們就可以使用IN 謂詞

IN(值1, 值2, 值3, …)來替換上述 SQL 語句。

SELECT product_name, purchase_price

FROM product

WHERE purchase_price IN (320, 500, 5000);

+————————+————————+

| product_name | purchase_price |

+————————+————————+

| T恤 | 500 |

| 打孔器 | 320 |

| 高壓鍋 | 5000 |

+————————+————————+

3 rows in set (0。00 sec)

上述語句簡潔了很多,可讀性大幅提高。

反之,希望選取出“進貨單價不是 320 元、 500 元、 5000 元”的商品時,可以使用否定形式NOT IN來實現。

SELECT product_name, purchase_price

FROM product

WHERE purchase_price NOT IN (320, 500, 5000);

+————————+————————+

| product_name | purchase_price |

+————————+————————+

| 運動T恤 | 2800 |

| 菜刀 | 2800 |

| 擦菜板 | 790 |

+————————+————————+

3 rows in set (0。00 sec)

需要注意的是,在使用IN 和 NOT IN 時是無法選取出NULL資料的。

實際結果也是如此,上述兩組結果中都不包含進貨單價為 NULL 的叉子和圓珠筆。 NULL 只能使用 IS NULL 和 IS NOT NULL 來進行判斷。

3.5.6 使用子查詢作為IN謂詞的引數

IN和子查詢

IN 謂詞(NOT IN 謂詞)具有其他謂詞所沒有的用法,那就是可以使用子查詢作為其引數。我們已經在 5-2 節中學習過了,子查詢就是 SQL內部生成的表,因此也可以說“能夠將表作為 IN 的引數”。同理,我們還可以說“能夠將檢視作為 IN 的引數”。

在此,我們建立一張新表

shopproduct

顯示出哪些商店銷售哪些商品。

—— DDL :建立表

DROP TABLE IF EXISTS shopproduct;

CREATE TABLE shopproduct

( shop_id CHAR(4) NOT NULL,

shop_name VARCHAR(200) NOT NULL,

product_id CHAR(4) NOT NULL,

quantity INTEGER NOT NULL,

PRIMARY KEY (shop_id, product_id) —— 指定主鍵

);

—— DML :插入資料

START TRANSACTION; —— 開始事務

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000A’, ‘東京’, ‘0001’, 30);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000A’, ‘東京’, ‘0002’, 50);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000A’, ‘東京’, ‘0003’, 15);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0002’, 30);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0003’, 120);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0004’, 20);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0006’, 10);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000B’, ‘名古屋’, ‘0007’, 40);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000C’, ‘大阪’, ‘0003’, 20);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000C’, ‘大阪’, ‘0004’, 50);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000C’, ‘大阪’, ‘0006’, 90);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000C’, ‘大阪’, ‘0007’, 70);

INSERT INTO shopproduct (shop_id, shop_name, product_id, quantity) VALUES (‘000D’, ‘福岡’, ‘0001’, 100);

COMMIT; —— 提交事務

SELECT * FROM shopproduct;

+————-+——————-+——————+——————+

| shop_id | shop_name | product_id | quantity |

+————-+——————-+——————+——————+

| 000A | 東京 | 0001 | 30 |

| 000A | 東京 | 0002 | 50 |

| 000A | 東京 | 0003 | 15 |

| 000B | 名古屋 | 0002 | 30 |

| 000B | 名古屋 | 0003 | 120 |

| 000B | 名古屋 | 0004 | 20 |

| 000B | 名古屋 | 0006 | 10 |

| 000B | 名古屋 | 0007 | 40 |

| 000C | 大阪 | 0003 | 20 |

| 000C | 大阪 | 0004 | 50 |

| 000C | 大阪 | 0006 | 90 |

| 000C | 大阪 | 0007 | 70 |

| 000D | 福岡 | 0001 | 100 |

+————-+——————-+——————+——————+

13 rows in set (0。00 sec)

由於單獨使用商店編號(shop_id)或者商品編號(product_id)不能區分表中每一行資料

,因此指定了 2 列作為主鍵(primary key)對商店和商品進行組合,用來唯一確定每一行資料。

假設我麼需要取出大阪在售商品的銷售單價,該如何實現呢?

第一步,取出大阪門店的在售商品 `product_id ;

第二步,取出大阪門店在售商品的銷售單價 `sale_price

—— step1:取出大阪門店的在售商品 `product_id`

SELECT product_id

FROM shopproduct

WHERE shop_id = ‘000C’;

+——————+

| product_id |

+——————+

| 0003 |

| 0004 |

| 0006 |

| 0007 |

+——————+

4 rows in set (0。00 sec)

上述語句取出了大阪門店的在售商品編號,接下來,我麼可以使用上述語句作為第二步的查詢條件來使用了。

—— step2:取出大阪門店在售商品的銷售單價 `sale_price`

SELECT product_name, sale_price

FROM product

WHERE product_id IN (SELECT product_id

FROM shopproduct

WHERE shop_id = ‘000C’);

+————————+——————+

| product_name | sale_price |

+————————+——————+

| 運動T恤 | 4000 |

| 菜刀 | 3000 |

| 叉子 | 500 |

| 擦菜板 | 880 |

+————————+——————+

4 rows in set (0。00 sec)

根據第5章學習的知識,子查詢是從最內層開始執行的(由內而外),因此,上述語句的子查詢執行之後,sql 展開成下面的語句

—— 子查詢展開後的結果

SELECT product_name, sale_price

FROM product

WHERE product_id IN (‘0003’, ‘0004’, ‘0006’, ‘0007’);

+————————+——————+

| product_name | sale_price |

+————————+——————+

| 運動T恤 | 4000 |

| 菜刀 | 3000 |

| 叉子 | 500 |

| 擦菜板 | 880 |

+————————+——————+

4 rows in set (0。00 sec)

可以看到,子查詢轉換之後變為 in 謂詞用法,你理解了嗎?

或者,你會疑惑既然 in 謂詞也能實現,那為什麼還要使用子查詢呢?這裡給出兩點原因:

①:實際生活中,某個門店的在售商品是不斷變化的,使用 in 謂詞就需要經常更新 sql 語句,降低了效率,提高了維護成本;

②:實際上,某個門店的在售商品可能有成百上千個,手工維護在售商品編號真是個大工程。

使用子查詢即可保持 sql 語句不變,極大提高了程式的可維護性,這是系統開發中需要重點考慮的內容。

NOT IN和子查詢

NOT IN 同樣支援子查詢作為引數,用法和 in 完全一樣。

—— NOT IN 使用子查詢作為引數,取出未在大阪門店銷售的商品的銷售單價

SELECT product_name, sale_price

FROM product

WHERE product_id NOT IN (SELECT product_id

FROM shopproduct

WHERE shop_id = ‘000A’);

+————————+——————+

| product_name | sale_price |

+————————+——————+

| 菜刀 | 3000 |

| 高壓鍋 | 6800 |

| 叉子 | 500 |

| 擦菜板 | 880 |

| 圓珠筆 | 100 |

+————————+——————+

5 rows in set (0。00 sec)

3.5.7 EXIST 謂詞

EXIST 謂詞的用法理解起來有些難度。

① EXIST 的使用方法與之前的都不相同

② 語法理解起來比較困難

③ 實際上即使不使用 EXIST,基本上也都可以使用 IN(或者 NOT IN)來代替

這麼說的話,還有學習 EXIST 謂詞的必要嗎?答案是肯定的,因為一旦能夠熟練使用 EXIST 謂詞,就能體會到它極大的便利性。

不過,你不用過於擔心,本課程介紹一些基本用法,日後學習時可以多多留意 EXIST 謂詞的用法,以期能夠在達到 SQL 中級水平時掌握此用法。

EXIST謂詞的使用方法

謂詞的作用就是

“判斷是否存在滿足某種條件的記錄”

如果存在這樣的記錄就返回真(TRUE),如果不存在就返回假(FALSE)。

EXIST(存在)謂詞的主語是“記錄”。

我們繼續以 IN和子查詢 中的示例,使用 EXIST 選取出大阪門店在售商品的銷售單價。

SELECT product_name, sale_price

FROM product AS p

WHERE EXISTS (SELECT *

FROM shopproduct AS sp

WHERE sp。shop_id = ‘000C’

AND sp。product_id = p。product_id);

+————————+——————+

| product_name | sale_price |

+————————+——————+

| 運動T恤 | 4000 |

| 菜刀 | 3000 |

| 叉子 | 500 |

| 擦菜板 | 880 |

+————————+——————+

4 rows in set (0。00 sec)

EXIST的引數

之前我們學過的謂詞,基本上都是像“列 LIKE 字串”或者“ 列 BETWEEN 值 1 AND 值 2”這樣需要指定 2 個以上的引數,而 EXIST 的左側並沒有任何引數。因為 EXIST 是隻有 1 個引數的謂詞。 所以,EXIST 只需要在右側書寫 1 個引數,該引數通常都會是一個子查詢。

(SELECT *

FROM shopproduct AS sp

WHERE sp。shop_id = ‘000C’

AND sp。product_id = p。product_id)

上面這樣的子查詢就是唯一的引數。確切地說,由於透過條件“SP。product_id = P。product_id”將 product 表和 shopproduct表進行了聯接,因此作為引數的是關聯子查詢。 EXIST 通常會使用關聯子查詢作為引數。

子查詢中的SELECT *

由於 EXIST 只關心記錄是否存在,因此返回哪些列都沒有關係。 EXIST 只會判斷是否存在滿足子查詢中 WHERE 子句指定的條件“商店編號(shop_id)為 ‘000C’,商品(product)表和商店商品(shopproduct)表中商品編號(product_id)相同”的記錄,只有存在這樣的記錄時才返回真(TRUE)。

因此,使用下面的查詢語句,查詢結果也不會發生變化。

SELECT product_name, sale_price

FROM product AS p

WHERE EXISTS (SELECT 1 —— 這裡可以書寫適當的常數

FROM shopproduct AS sp

WHERE sp。shop_id = ‘000C’

AND sp。product_id = p。product_id);

+————————+——————+

| product_name | sale_price |

+————————+——————+

| 運動T恤 | 4000 |

| 菜刀 | 3000 |

| 叉子 | 500 |

| 擦菜板 | 880 |

+————————+——————+

4 rows in set (0。00 sec)

大家可以把在 EXIST 的子查詢中書寫 SELECT * 當作 SQL 的一種習慣。

使用NOT EXIST替換NOT IN

就像 EXIST 可以用來替換 IN 一樣, NOT IN 也可以用NOT EXIST來替換。

下面的程式碼示例取出,不在大阪門店銷售的商品的銷售單價。

SELECT product_name, sale_price

FROM product AS p

WHERE NOT EXISTS (SELECT *

FROM shopproduct AS sp

WHERE sp。shop_id = ‘000A’

AND sp。product_id = p。product_id);

+————————+——————+

| product_name | sale_price |

+————————+——————+

| 菜刀 | 3000 |

| 高壓鍋 | 6800 |

| 叉子 | 500 |

| 擦菜板 | 880 |

| 圓珠筆 | 100 |

+————————+——————+

5 rows in set (0。00 sec)

NOT EXIST 與 EXIST 相反,當“不存在”滿足子查詢中指定條件的記錄時返回真(TRUE)。

3.6 CASE 表示式

3.6.1 什麼是 CASE 表示式?

CASE 表示式是函式的一種。是 SQL 中數一數二的重要功能,有必要好好學習一下。

CASE 表示式是在區分情況時使用的,這種情況的區分在程式設計中通常稱為(條件)分支。

CASE表示式的語法分為簡單CASE表示式和搜尋CASE表示式兩種。由於搜尋CASE表示式包含簡單CASE表示式的全部功能。本課程將重點介紹搜尋CASE表示式。

語法:

CASE WHEN <求值表示式> THEN <表示式>

WHEN <求值表示式> THEN <表示式>

WHEN <求值表示式> THEN <表示式>

ELSE <表示式>

END

上述語句執行時,依次判斷 when 表示式是否為真值,是則執行 THEN 後的語句,如果所有的 when 表示式均為假,則執行 ELSE 後的語句。

無論多麼龐大的 CASE 表示式,最後也只會返回一個值。

3.5.2 CASE表示式的使用方法

假設現在 要實現如下結果:

A :衣服

B :辦公用品

C :廚房用具

因為表中的記錄並不包含“A : ”或者“B : ”這樣的字串,所以需要在 SQL 中進行新增。並將“A : ”“B : ”“C : ”與記錄結合起來。

應用場景1:根據不同分支得到不同列值

SELECT product_name,

CASE WHEN product_type = ‘衣服’ THEN CONCAT(‘A : ’,product_type)

WHEN product_type = ‘辦公用品’ THEN CONCAT(‘B : ’,product_type)

WHEN product_type = ‘廚房用具’ THEN CONCAT(‘C : ’,product_type)

ELSE NULL

END

AS abc_product_type

FROM product;

+————————+——————————+

| product_name | abc_product_type |

+————————+——————————+

| T恤 | A : 衣服 |

| 打孔器 | B : 辦公用品 |

| 運動T恤 | A : 衣服 |

| 菜刀 | C : 廚房用具 |

| 高壓鍋 | C : 廚房用具 |

| 叉子 | C : 廚房用具 |

| 擦菜板 | C : 廚房用具 |

| 圓珠筆 | B : 辦公用品 |

+————————+——————————+

8 rows in set (0。00 sec)

ELSE 子句也可以省略不寫,這時會被預設為 ELSE NULL。但為了防止有人漏讀,還是希望大家能夠顯示地寫出 ELSE 子句。

此外, CASE 表示式最後的“END”是不能省略的,請大家特別注意不要遺漏。忘記書寫 END 會發生語法錯誤,這也是初學時最容易犯的錯誤。

應用場景2:實現列方向上的聚合

通常我們使用如下程式碼實現行的方向上不同種類的聚合(這裡是 sum)

SELECT product_type,

SUM(sale_price) AS sum_price

FROM product

GROUP BY product_type;

+————————+——————-+

| product_type | sum_price |

+————————+——————-+

| 衣服 | 5000 |

| 辦公用品 | 600 |

| 廚房用具 | 11180 |

+————————+——————-+

3 rows in set (0。00 sec)

假如要在列的方向上展示不同種類額聚合值,該如何寫呢?

sum_price_clothes | sum_price_kitchen | sum_price_office

——————————+——————————-+————————-

5000 | 11180 | 600

聚合函式 + CASE WHEN 表示式即可實現該效果

—— 對按照商品種類計算出的銷售單價合計值進行行列轉換

SELECT SUM(CASE WHEN product_type = ‘衣服’ THEN sale_price ELSE 0 END) AS sum_price_clothes,

SUM(CASE WHEN product_type = ‘廚房用具’ THEN sale_price ELSE 0 END) AS sum_price_kitchen,

SUM(CASE WHEN product_type = ‘辦公用品’ THEN sale_price ELSE 0 END) AS sum_price_office

FROM product;

+——————————-+——————————-+——————————+

| sum_price_clothes | sum_price_kitchen | sum_price_office |

+——————————-+——————————-+——————————+

| 5000 | 11180 | 600 |

+——————————-+——————————-+——————————+

1 row in set (0。00 sec)

(擴充套件內容)應用場景3:實現行轉列

假設有如下圖表的結構

sql入門第一步(3)

計劃得到如下的圖表結構

sql入門第一步(3)

聚合函式 + CASE WHEN 表示式即可實現該轉換

—— CASE WHEN 實現數字列 score 行轉列

SELECT name,

SUM(CASE WHEN subject = ‘語文’ THEN score ELSE null END) as chinese,

SUM(CASE WHEN subject = ‘數學’ THEN score ELSE null END) as math,

SUM(CASE WHEN subject = ‘外語’ THEN score ELSE null END) as english

FROM score

GROUP BY name;

+————+————-+————+————-+

| name | chinese | math | english |

+————+————-+————+————-+

| 張三 | 93 | 88 | 91 |

| 李四 | 87 | 90 | 77 |

+————+————-+————+————-+

2 rows in set (0。00 sec)

上述程式碼實現了數字列 score 的行轉列,也可以實現文字列 subject 的行轉列

—— CASE WHEN 實現文字列 subject 行轉列

SELECT name,

MAX(CASE WHEN subject = ‘語文’ THEN subject ELSE null END) as chinese,

MAX(CASE WHEN subject = ‘數學’ THEN subject ELSE null END) as math,

MIN(CASE WHEN subject = ‘外語’ THEN subject ELSE null END) as english

FROM score

GROUP BY name;

+————+————-+————+————-+

| name | chinese | math | english |

+————+————-+————+————-+

| 張三 | 語文 | 數學 | 外語 |

| 李四 | 語文 | 數學 | 外語 |

+————+————-+————+————-+

2 rows in set (0。00 sec

總結:

當待轉換列為數字時,可以使用

SUM AVG MAX MIN

等聚合函式;

當待轉換列為文字時,可以使用

MAX MIN

等聚合函式

標簽: product  檢視  null  id  shop