SQL謂詞與CASE表示式
什麼是謂詞
謂詞就是返回值為真值的函式。對於通常的函式來說,返回值有可能是數字、字串和日期等,但是謂詞的返回值全部是真值。這也是謂詞和函式的最大區別。
謂詞主要有以下幾種:
- LIKE
- BETWEEN
- IS NULL、IS NOT NULL
- IN
- EXISTS
LIKE謂詞—字串的部分一致查詢
截止目前,我們使用字串作為查詢條件的例子使用的都是=。這裡的=只有在字串完全一致時才為真。與之相反,LIKE謂詞更加模糊一些,當需要進行字串的部分一致查詢時需要使用該謂詞。
部分一致大體可以分為前方一致、中間一致和後方一致三種類型。接下來就讓我們看一看具體示例吧。
首先,我們先建立一張用作示例的表:
--建立SampleLike表 CREATE TABLE SampleLike ( strcol VARCHAR(6) NOT NULL, PRIMARY KEY(strcol));
向表中插入資料
--插入資料 BEGIN TRANSACTION;BEGIN INSERT INTO SampleLike VALUES ('abcddd');INSERT 0 1 INSERT INTO SampleLike VALUES ('dddabc');INSERT 0 1 INSERT INTO SampleLike VALUES ('abdddc');INSERT 0 1 INSERT INTO SampleLike VALUES ('abcdd');INSERT 0 1 INSERT INTO SampleLike VALUES ('ddabc');INSERT 0 1 INSERT INTO SampleLike VALUES ('abddc');INSERT 0 1 COMMIT;COMMIT
確認一下我們建立的表的內容:
SELECT * FROM SampleLike;
執行結果:
strcol--------
abcddd
dddabc
abdddc
abcdd
ddabc
abddc
(6 行記錄)
前方一致查詢
使用Like進行前方一致查詢
SELECT * FROM SampleLike
WHERE strcol LIKE 'ddd%';
執行結果:
strcol--------
dddabc
(1 行記錄)
其中的%代表“0字元以上的任意字元”的特殊符號,上例表示“以ddd開頭的所有字元”。
中間一致查詢
使用LIKE進行中間一致查詢
SELECT * FROM SampleLike WHERE strcol LIKE '%ddd%';
執行結果:
strcol--------
abcddd
dddabc
abdddc
(3 行記錄)
在字串的起始和結束位置加上%,就能取出“包含ddd的字串”。
後方一致查詢
使用LIKE進行後方一致查詢
SELECT * FROM SampleLike
WHERE strcol LIKE '%ddd';
執行結果:
strcol--------
abcddd
(1 行記錄)
此外,我們還可以使用_(下劃線)來代替%,與%不同的是,它代表“任意一個字元”,下面我們就來嘗試一下:
--使用LIKE和_(下劃線)進行後方一致查詢
SELECT * FROM SampleLike
WHERE strcol LIKE 'abc__';
執行結果:
strcol--------
abcdd
(1 行記錄)
再舉個例子:
--查詢'abc+任意3個字元'的字串
SELECT * FROM SampleLike
WHERE strcol LIKE 'abc___';
執行結果:
strcol--------
abcddd
(1 行記錄)
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 行記錄)
BETWEEN的特點就是結果會包含100和1000這兩個臨界值。如果不想讓結果包含臨界值,那就必須使用<和>。
--選取出銷售單價為101~999元的商品
SELECT product_name, sale_price
FROM Product
WHERE sale_price > 100
AND sale_price < 1000;
執行結果:
product_name | sale_price--------------+------------
打孔器 | 500
叉子 | 500
擦菜板 | 880
(3 行記錄)
IS NULL、IS NOT NULL—判斷是否為NULL
為了選取某些值為NULL的列的資料,不能使用=,而只能使用特定的謂詞IS NULL。
--選取出進貨單價為NULL的商品
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price IS NULL;
執行結果:
product_name | purchase_price--------------+----------------
叉子 |
圓珠筆 |
(2 行記錄)
與之相反,如果選取NULL以外的資料,需要使用謂詞IS NOT NULL。
--選取出進貨單價不為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 行記錄)
IN謂詞—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 行記錄)
我們使用IN 謂詞來替換上述SQL語句:
--通過IN來指定多個進貨單價進行查詢
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price IN (320, 500, 5000);
執行結果:
product_name | purchase_price--------------+----------------
T衫 | 500
打孔器 | 320
高壓鍋 | 5000
(3 行記錄)
反之,否定形式可以使用NOT IN來實現:
--使用NOT IN 進行查詢時指多個排除的進貨單價進行查詢
SELECT product_name, purchase_price
FROM Product
W HERE purchase_price NOT IN (320, 500, 5000);
執行結果:
product_name | purchase_price--------------+----------------
運動T衫 | 2800
菜刀 | 2800
擦菜板 | 790
(3 行記錄)
註釋:使用IN 和NOT IN 時是無法取出NULL資料的,NULL終究是需要使用IS NULL和IS NOT NULL來進行判斷。
使用子查詢作為IN謂詞的引數
IN謂詞和子查詢
IN謂詞(NOT IN謂詞)具有其他謂詞所沒有的用法,那就是可以使用子查詢來作為其引數。子查詢在之前已經學過,就是SQL內部生成的表。
為了掌握更詳盡的使用方法,我們再建立一張新表:
--建立ShopProduct(商店商品)表的CREATE TABLE語句
CREATE TABLE ShopProduct
( shop_id CHAR(4) NOT NULL,
shop_name VARCHAR(200) NOT NULL,
product_id CHAR(4) NOT NULL,
quantit INTEGER NOT NULL,
PRIMARY KEY(shop_id, product_id));
向表ShopProduct中插入資料
--向表ShopProduct中插入資料的INSERT語句
BEGIN TRANSACTION;BEGIN
INSERT INTO ShopProduct VALUES('000A', '成華區', '0001', 30);INSERT 0 1
INSERT INTO ShopProduct VALUES('000A', '成華區', '0002', 50);INSERT 0 1
INSERT INTO ShopProduct VALUES('000A', '成華區', '0003', 15);INSERT 0 1
INSERT INTO ShopProduct VALUES('000B', '金牛區', '0002', 30);INSERT 0 1
INSERT INTO ShopProduct VALUES('000B', '金牛區', '0003', 120);INSERT 0 1
INSERT INTO ShopProduct VALUES('000B', '金牛區', '0004', 20);INSERT 0 1
INSERT INTO ShopProduct VALUES('000B', '金牛區', '0006', 10);INSERT 0 1
INSERT INTO ShopProduct VALUES('000B', '金牛區', '0007', 40);INSERT 0 1
INSERT INTO ShopProduct VALUES('000C', '武侯區', '0003', 20);INSERT 0 1
INSERT INTO ShopProduct VALUES('000C', '武侯區', '0004', 50);INSERT 0 1
INSERT INTO ShopProduct VALUES('000C', '武侯區', '0006', 90);INSERT 0 1
INSERT INTO ShopProduct VALUES('000C', '武侯區', '0007', 70);INSERT 0 1
INSERT INTO ShopProduct VALUES('000D', '錦江區', '0001', 100);INSERT 0 1
COMMIT;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 行記錄)
使用子查詢作為IN謂詞的引數:
--取得“在武侯區銷售的商品的銷售單價”
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 行記錄)
如果在SELECT語句中使用了子查詢,那麼即使資料發生了變更,還可以繼續使用同樣的SELECT語句。像這樣能夠應對資料變更的程式,稱為‘易維護程式’。
NOT 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 行記錄)
EXISTS謂詞
EXISTS謂詞的使用方法
一言以蔽之,謂詞的作用就是“判斷是否存在某種滿足條件的記錄”。如果存在這樣的記錄就返回真(TRUE),如果不存在這樣的記錄就返回假(FALSE)。EXISTS(存在)謂詞的主語是“記錄”。
--使用EXISTS選取出“武侯區在售商品的銷售單價”
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 行記錄)
註釋:
- 通常指定關聯子查詢作為EXISTS的引數。
- 作為EXISTS引數的子查詢中通常使用SELECT *。
使用NOT EXISTS替換NOT IN
就像EXISTS可以替換IN一樣,NOT IN 也可以用NOT EXISTS 來替換。
--使用NOT EXISTS 讀取出“成華區店在售之外的商品的銷售單價”
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 行記錄)
CASE表示式
什麼是CASE表示式
CASE表示式是一種進行運算的功能,它是SQL中最重要的功能之一。CASE表示式是在區分情況下使用,這種情況的區分在程式設計中通常叫做條件(分支)。類似於C語言中的if……else….語句。
CASE表示式的語法
CASE表示式的語法分為簡單CASE表示式和搜尋CASE表示式兩種。但是搜尋CASE表示式包含了簡單CASE表示式的全部功能,所以我們學習搜尋CASE表示式的語法就可以了。
--搜尋CASE表示式
CASE WHEN <求值表示式> THEN <表示式>
WHEN <求值表示式> THEN <表示式>
WHEN <求值表示式> THEN <表示式>
.....
ELSE <表示式>
END
CASE表示式會從最初的WHEN子句中的“ <求值表示式> ”進行求值運算。所謂求值,就是要調查該表示式的真值是什麼,如果結果為真(TRUE),那麼就返回THEN子句中的表示式,CASE表示式的執行到此為止。如果結果不為真,那麼就跳轉到下一條的WHEN子句的求值之中。如果知道最後的WHEN子句為止返回結果都不為真,那麼就會返回ELSE中的表示式,執行結束。
CASE表示式的使用方法
咱們用一個例子說明:
--通過CASE表示式將A~C的字串加入到商品種類中
SELECT product_name, CASE WHEN product_type = '衣服'
THEN 'A:' || product_type
WHEN product_type = '辦公用品'
THEN 'B:' || product_type
WHEN product_type = '廚房用具'
THEN 'C:' || product_type
ELSE NULL
END AS abs_product_type
FROM Product;
執行結果:
product_name | abs_product_type--------------+------------------
T衫 | A:衣服
打孔器 | B:辦公用品
運動T衫 | A:衣服
菜刀 | C:廚房用具
高壓鍋 | C:廚房用具
叉子 | C:廚房用具
擦菜板 | C:廚房用具
圓珠筆 | B:辦公用品
(8 行記錄)
註釋:
- 雖然CASE表示式中的ELSE子句可以省略,但是最好不要省略。
- CASE表示式中的END不能省略。
CASE表示式可以實現行列互換
使用GRUOP BY無法實現行列轉換:
SELECT product_type, SUM(sale_price) AS sum_price
FROM Product
GROUP BY product_type;
執行結果:
product_type | sum_price--------------+-----------
衣服 | 5000
辦公用品 | 600
廚房用具 | 11180
(3 行記錄)
但是使用CASE表示式可以實現行列轉換
--對照商品種類計算出的銷售單價合計值進行行列轉換
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 行記錄)
今天的學習到此結束。加油!