1. 程式人生 > 其它 >SQL 算術運算子和比較運算子

SQL 算術運算子和比較運算子

目錄

學習重點

  • 運算子就是對其兩邊的列或者值進行運算(計算或者比較大小等)的符號。

  • 使用算術運算子可以進行四則運算。

  • 括號可以提升運算的優先順序(優先進行運算)。

  • 包含 NULL 的運算,其結果也是 NULL

  • 比較運算子可以用來判斷列或者值是否相等,還可以用來比較大小。

  • 判斷是否為 NULL,需要使用 IS NULL 或者 IS NOT NULL 運算子。

一、算術運算子

SQL 語句中可以使用計算表示式。程式碼清單 17 中的 SELECT

語句,把各個商品單價的 2 倍(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 列被定為字串型別,並且在對字串型別的資料進行大小比較時,使用的是和數字比較不同的規則。典型的規則就是按照字典順序進行比較,也就是像姓名那樣,按照條目在字典中出現的順序來進行排序。該規則最重要的一點就是,以相同字元開頭的單詞比不同字元開頭的單詞更相近。

Charschr 列中的資料按照字典順序進行排序的結果如下所示。

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 提供了專門用來判斷是否為 NULLIS 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 使用比較運算子的方法還有很多,詳細內容將會在 各種各樣的函式 中進行介紹。

請參閱

(完)


  1. 在 Oracle 中,FROM 子句是必需的,這種情況下可以使用 DUAL 這個臨時表。另外,DB2 中可以使用 SYSIBM.SYSDUMMY1 這個臨時表。 ↩︎

  2. 有很多 RDBMS 可以使用比較運算子“!=”來實現不等於功能。但這是限於不被標準 SQL 所承認的特定 SQL,出於安全的考慮,最好不要使用。 ↩︎

  3. 該規則對定長字串和可變長字串都適用。 ↩︎

  4. SQL 不識別“= NULL”和“<> NULL”的理由將會在 邏輯運算子(包含 NULL 情況下的真值)中進行說明。 ↩︎