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