SQL 算術運算子和比較運算子
學習重點
運算子就是對其兩邊的列或者值進行運算(計算或者比較大小等)的符號。
使用算術運算子可以進行四則運算。
括號可以提升運算的優先順序(優先進行運算)。
包含
NULL
的運算,其結果也是NULL
。比較運算子可以用來判斷列或者值是否相等,還可以用來比較大小。
判斷是否為
NULL
,需要使用IS NULL
或者IS NOT NULL
運算子。
一、算術運算子
SQL 語句中可以使用計算表示式。程式碼清單 17 中的 SELECT
sale_price
的 2 倍)以 "sale_price_x2
" 列的形式讀取出來。
程式碼清單 17 SQL語句中也可以使用運算表示式
SELECT product_name, sale_price,
sale_price * 2 AS "sale_price_x2"
FROM Product;
執行結果
product_name | sale_price | sale_price_x2 ---------------+-------------+---------------- T恤衫 | 1000 | 2000 打孔器 | 500 | 1000 運動T恤 | 4000 | 8000 菜刀 | 3000 | 6000 高壓鍋 | 6800 | 13600 叉子 | 500 | 1000 擦菜板 | 880 | 1760 圓珠筆 | 100 | 200
sale_price_x2
列中的 sale_price * 2
就是計算銷售單價的 2 倍的表示式。以 product_name
列的值為 'T 恤衫'
的記錄行為例,sale_price
列的值 1000 的 2 倍是 2000,它以 sale_price_x2
列的形式被查詢出來。同樣,'打孔器'
記錄行的值 500 的 2 倍 1000,'運動 T 恤'
記錄行的值 4000 的 2 倍 8000,都被查詢出來了。運算就是這樣以行為單位執行的。
SQL 語句中可以使用的四則運算的主要運算子如表 1 所示。
表 1 SQL 語句中可以使用的四則運算的主要運算子
含義 | 運算子 |
---|---|
加法運算 | + |
減法運算 | - |
乘法運算 | * |
除法運算 | / |
KEYWORD
+
運算子
-
運算子
*
運算子
/
運算子
四則運算所使用的運算子(+
、-
、*
、/
)稱為算術運算子。運算子就是使用其兩邊的值進行四則運算或者字串拼接、數值大小比較等運算,並返回結果的符號。加法運算子(+
)前後如果是數字或者數字型別的列名的話,就會返回加法運算後的結果。SQL 中除了算術運算子之外還有其他各種各樣的運算子。
KEYWORD
算術運算子
運算子
法則 6
SELECT
子句中可以使用常數或者表示式。
當然,SQL 中也可以像平常的運算表示式那樣使用括號 ()
。括號中運算表示式的優先順序會得到提升,優先進行運算。例如在運算表示式 (1 + 2) * 3
中,會先計算 1 + 2
的值,然後再對其結果進行 * 3
運算。
KEYWORD
()
括號的使用並不僅僅侷限於四則運算,還可以用在 SQL 語句的任何表示式當中。具體的使用方法今後會慢慢介紹給大家。
二、需要注意 NULL
像程式碼清單 17 那樣,SQL 語句中進行運算時,需要特別注意含有 NULL
的運算。請大家考慮一下在 SQL 語句中進行如下運算時,結果會是什麼呢?
A. 5 + NULL
B. 10 - NULL
C. 1 * NULL
D. 4 / NULL
E. NULL / 9
F. NULL / 0
正確答案全部都是 NULL
。大家可能會覺得奇怪,為什麼會這樣呢?實際上所有包含 NULL
的計算,結果肯定是 NULL
。即使像 F 那樣用 NULL
除以 0 時這一原則也適用。通常情況下,類似 5/0
這樣除數為 0 的話會發生錯誤,只有 NULL
除以 0 時不會發生錯誤,並且結果還是 NULL
。
儘管如此,很多時候我們還是希望 NULL
能像 0 一樣,得到 5 + NULL = 5
這樣的結果。不過也不要緊,SQL 中也為我們準備了可以解決這類情況的方法(將會在 各種各樣的函式 中進行介紹)。
專欄
FROM 子句真的有必要嗎?
在 SELECT 語句基礎 中我們介紹過
SELECT
語句是由SELECT
子句和FROM
子句組成的。可實際上FROM
子句在SELECT
語句中並不是必不可少的,只使用SELECT
子句進行計算也是可以的。程式碼清單 A 只包含
SELECT
子句的SELECT
語句-- SQL Server PostgreSQL MySQL SELECT (100 + 200) * 3 AS calculation;
執行結果
calculation ------------- 900
實際上,通過執行
SELECT
語句來代替計算器的情況基本上是不存在的。不過在極少數情況下,還是可以通過使用沒有FROM
子句的SELECT
語句來實現某種業務的。例如,不管內容是什麼,只希望得到一行臨時資料的情況。但是也存在像 Oracle 這樣不允許省略
SELECT
語句中的FROM
子句的 RDBMS,請大家注意 [1]。
三、比較運算子
在 SELECT 語句基礎 學習 WHERE
子句時,我們使用符號 =
從 Product
表中選取出了商品種類(product_type
)為字串 '衣服'
的記錄。下面讓我們再使用符號 =
選取出銷售單價(sale_price
)為 500 日元(數字 500)的記錄(程式碼清單 18)。
程式碼清單 18 選取出 sale_price
列為 500 的記錄
SELECT product_name, product_type
FROM Product
WHERE sale_price = 500;
執行結果
product_name | product_type
---------------+--------------
打孔器 | 辦公用品
叉子 | 廚房用具
像符號 =
這樣用來比較其兩邊的列或者值的符號稱為比較運算子,符號 =
就是比較運算子。在 WHERE
子句中通過使用比較運算子可以組合出各種各樣的條件表示式。
接下來,我們使用“不等於”這樣代表否定含義的比較運算子 <>
[2],選取出 sale_price
列的值不為 500 的記錄(程式碼清單 19)。
KEYWORD
比較運算子
=
運算子
<>
運算子
程式碼清單 19 選取出 sale_price
列的值不是 500 的記錄
SELECT product_name, product_type
FROM Product
WHERE sale_price <> 500;
執行結果
product_name | product_type
---------------+--------------
T恤衫 | 衣服
運動T恤 | 衣服
菜刀 | 廚房用具
高壓鍋 | 廚房用具
擦菜板 | 廚房用具
圓珠筆 | 辦公用品
SQL 中主要的比較運算子如表 2 所示,除了等於和不等於之外,還有進行大小比較的運算子。
表 2 比較運算子
運算子 | 含義 |
---|---|
= |
和 ~ 相等 |
<> |
和 ~ 不相等 |
>= |
大於等於 ~ |
> |
大於 ~ |
<= |
小於等於 ~ |
< |
小於 ~ |
KEYWORD
=
運算子
<>
運算子
>=
運算子
>
運算子
<=
運算子
<
運算子
這些比較運算子可以對字元、數字和日期等幾乎所有資料型別的列和值進行比較。例如,從 Product
表中選取出銷售單價(sale_price
) 大於等於 1000 日元的記錄,或者登記日期(regist_date
)在 2009 年 9 月 27 日之前的記錄,可以使用比較運算子 >=
和 <
,在 WHERE
子句中生成如下條件表示式(程式碼清單 20、程式碼清單 21)。
程式碼清單 20 選取出銷售單價大於等於 1000 日元的記錄
SELECT product_name, product_type, sale_price
FROM Product
WHERE sale_price >= 1000;
執行結果
product_name | product_type | sale_price
---------------+--------------+--------------
T恤衫 | 衣服 | 1000
運動T恤 | 衣服 | 4000
菜刀 | 廚房用具 | 3000
高壓鍋 | 廚房用具 | 6800
程式碼清單 21 選取出登記日期在 2009 年 9 月27日 之前的記錄
SELECT product_name, product_type, regist_date
FROM Product
WHERE regist_date < '2009-09-27';
執行結果
product_name | product_type | regist_date
---------------+--------------+-----------
T恤衫 | 衣服 | 2009-09-20
打孔器 | 辦公用品 | 2009-09-11
菜刀 | 廚房用具 | 2009-09-20
高壓鍋 | 廚房用具 | 2009-01-15
叉子 | 廚房用具 | 2009-09-20
擦菜板 | 廚房用具 | 2008-04-28
小於某個日期就是在該日期之前的意思。想要實現在某個特定日期(包含該日期)之後的查詢條件時,可以使用代表大於等於的 >=
運算子。
另外,在使用大於等於(>=
)或者小於等於(<=
)作為查詢條件時,一定要注意不等號(<
、>
)和等號(=
)的位置不能顛倒。一定要讓不等號在左,等號在右。如果寫成(=<
)或者(=>
)就會出錯。當然,代表不等於的比較運算子也不能寫成(><
)。
法則 7
使用比較運算子時一定要注意不等號和等號的位置。
除此之外,還可以使用比較運算子對計算結果進行比較。程式碼清單 22 在 WHERE
子句中指定了銷售單價(sale_price
)比進貨單價(purchase_price
)高出 500 日元以上的條件表示式。為了判斷是否高出 500 日元,需要用 sale_price
列的值減去 purchase_price
列的值。
程式碼清單 22 WHERE
子句的條件表示式中也可以使用計算表示式
SELECT product_name, sale_price, purchase_price
FROM Product
WHERE sale_price - purchase_price >= 500;
執行結果
product_name | sale_price | purchase_price
---------------+-------------+---------------
T恤衫 | 1000 | 500
運動T恤 | 4000 | 2800
高壓鍋 | 6800 | 5000
四、對字串使用不等號時的注意事項
對字串使用大於等於或者小於等於不等號時會得到什麼樣的結果呢?接下來我們使用表 3 中的 Chars
表來進行確認。雖然該表中儲存的都是數字,但 chr
是字串型別(CHAR
型別)的列。
表 3 Chars
表
chr(字串型別) |
---|
1 |
2 |
3 |
10 |
11 |
222 |
可以使用程式碼清單 23 中的 SQL 語句來建立 Chars
表。
程式碼清單 23 建立 Chars
表並插入資料
-- DDL :建立表
CREATE TABLE Chars
(chr CHAR(3) NOT NULL,
PRIMARY KEY (chr));
-- SQL Server PostgreSQL
-- DML :插入資料
BEGIN TRANSACTION; -------------①
INSERT INTO Chars VALUES ('1');
INSERT INTO Chars VALUES ('2');
INSERT INTO Chars VALUES ('3');
INSERT INTO Chars VALUES ('10');
INSERT INTO Chars VALUES ('11');
INSERT INTO Chars VALUES ('222');
COMMIT;
特定的 SQL
程式碼清單 23 中的 DML 語句根據 DBMS 的不同而略有差異。在 MySQL 中執行該語句時,請大家把 ① 的部分改成“
START TRANSACTION;
”。在 Oracle 和 DB2 中執行時不需用到 ① 的部分,請刪除。
那麼,對 Chars
表執行程式碼清單 24 中的 SELECT
語句(查詢條件是 chr
列大於 '2'
)會得到什麼樣的結果呢?
程式碼清單 24 選取出大於 '2'
的資料的 SELECT
語句
SELECT chr
FROM Chars
WHERE chr > '2';
大家是不是覺得應該選取出比 2 大的 3、10、11 和 222 這 4 條記錄呢?下面就讓我們來看看該 SELECT
語句的執行結果吧。
執行結果
chr
-----
3
222
沒想到吧?是不是覺得 10 和 11 比 2 大,所以也應該選取出來呢?大家之所以這樣想,是因為混淆了數字和字串,也就是說 2 和 '2'
並不一樣。
現在,chr
列被定為字串型別,並且在對字串型別的資料進行大小比較時,使用的是和數字比較不同的規則。典型的規則就是按照字典順序進行比較,也就是像姓名那樣,按照條目在字典中出現的順序來進行排序。該規則最重要的一點就是,以相同字元開頭的單詞比不同字元開頭的單詞更相近。
Chars
表 chr
列中的資料按照字典順序進行排序的結果如下所示。
1
10
11
2
222
3
'10'
和 '11'
同樣都是以 '1'
開頭的字串,首先判定為比 '2'
小。這就像在字典中“提問”“提議”和“問題”按照如下順序排列一樣。
提問
提議
問題
或者我們以書籍的章節為例也可以。1-1 節包含在第 1 章當中,所以肯定比第 2 章更靠前。
1
1-1
1-2
1-3
2
2-1
2-2
3
進行大小比較時,得到的結果是 '1-3'
比 '2'
小('1-3' < '2'
),'3'
大於 '2-2'
('3' > '2'
)。
比較字串型別大小的規則今後還會經常使用,所以請大家牢記 [3]。
法則 8
字串型別的資料原則上按照字典順序進行排序,不能與數字的大小順序混淆。
五、不能對 NULL
使用比較運算子
關於比較運算子還有一點十分重要,那就是作為查詢條件的列中含有 NULL
的情況。例如,我們把進貨單價(purchase_price
)作為查詢條件。請注意,商品“叉子”和“圓珠筆”的進貨單價是 NULL
。
我們先來選取進貨單價為 2800 日元(purchase_price = 2800
)的記錄(程式碼清單 25)。
程式碼清單 25 選取進貨單價為 2800 日元的記錄
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price = 2800;
執行結果
product_name | purchase_price
---------------+---------------
運動T恤 | 2800
菜刀 | 2800
大家對這個結果應該都沒有疑問吧?接下來我們再嘗試選取出進貨單價不是 2800 日元(purchase_price <> 2800
)的記錄(程式碼清單 26)。
程式碼清單 26 選取出進貨單價不是 2800 日元的記錄
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price <> 2800;
執行結果
product_name | purchase_price
---------------+---------------
T恤衫 | 500
打孔器 | 320
高壓鍋 | 5000
擦菜板 | 790
執行結果中並沒有“叉子”和“圓珠筆”。這兩條記錄由於進貨單價不明(NULL
),因此無法判定是不是 2800 日元。
那如果想選取進貨單價為 NULL
的記錄的話,條件表示式該怎麼寫呢?歷經一番苦思冥想後,用“purchase_price = NULL
”試了試,還是一條記錄也取不出來。
程式碼清單 27 錯誤的 SELECT
語句(一條記錄也取不出來)
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price = NULL;
執行結果
即使使用 <>
運算子也還是無法選取出 NULL
的記錄 [4]。因此,SQL 提供了專門用來判斷是否為 NULL
的 IS NULL
運算子。想要選取 NULL
的記錄時,可以像程式碼清單 28 那樣來書寫條件表示式。
KEYWORD
IS NULL
運算子
程式碼清單 28 選取 NULL
的記錄
SELECT product_name, purchase_price
FROM Product
WHERE purchase_price IS NULL;
執行結果
product_name | purchase_price
---------------+---------------
叉子 |
圓珠筆 |
反之,希望選取不是 NULL
的記錄時,需要使用 IS NOT NULL
運算子(程式碼清單 29)。
KEYWORD
IS NOT NULL
運算子
程式碼清單 29 選取不為 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
法則 9
希望選取
NULL
記錄時,需要在條件表示式中使用IS NULL
運算子。希望選取不是NULL
的記錄時,需要在條件表示式中使用IS NOT NULL
運算子。
除此之外,對 NULL
使用比較運算子的方法還有很多,詳細內容將會在 各種各樣的函式 中進行介紹。
請參閱
(完)