11.1 函數
SQL支持利用函數來處理數據。函數一般是在數據上執行的,它給數據的轉換和處理提供了方便。
函數沒有SQL的可移植性強:能運行在多個系統上的代碼稱爲可移植的( portable)。相對來說,多數SQL語句是可移植的,在SQL實現之間有差異時,這些差異通常不那麼難處理。而函數的可移植性卻不強。幾乎每種主要的DBMS的實現都支持其他實現不支持的函數,而且有時差異還很大。爲了代碼的可移植,許多SQL程序員不贊成使用特殊實現的功能。雖然這樣做很有好處,但不總是利於應用程序的性能。如果不使用這些函數,編寫某些應用程序代碼會很艱難。必須利用其他方法來實現DBMS非常有效地完成的工作。如果你決定使用函數,應該保證做好代碼註釋,以便以後你(或其他人)能確切地知道所編寫SQL代碼的含義。
11.2 使用函數
大多數SQL實現支持以下類型的函數。
用於處理文本串(如刪除或填充值,轉換值爲大寫或小寫)的文本函數。
- 用於在數值數據上進行算術操作(如返回絕對值,進行代數運算)
的數值函數。 - 用於處理日期和時間值並從這些值中提取特定成分(例如,返回
兩個日期之差,檢查日期有效性等)的日期和時間函數。 - 返回DBMS正使用的特殊信息(如返回用戶登錄信息,檢查版本
細節)的系統函數。
11.2.1 文本處理函數
我們已經看過一個文本處理函數的例子,其中使用RTrim()
函數來去除列值右邊的空格。下面是另一個例子,這次使用Upper()
函數:
mysql> SELECT vend_name, Upper(vend_name) AS vend_name_upcase FROM vendors ORDER BY vend_name;
+----------------+------------------+
| vend_name | vend_name_upcase |
+----------------+------------------+
| ACME | ACME |
| Anvils R Us | ANVILS R US |
| Furball Inc. | FURBALL INC. |
| Jet Set | JET SET |
| Jouets Et Ours | JOUETS ET OURS |
| LT Supplies | LT SUPPLIES |
+----------------+------------------+
- 分析:正如所見,
Upper()
將文本轉換爲大寫,因此本例子中每個供應商都列出兩次,第一次爲vendors
表中存儲的值,第二次作爲列vend_name_upcase
轉換爲大寫。
函 數 | 說 明 |
---|---|
Left() | 返回串左邊的字符 |
Length() | 返回串的長度 |
Locate() | 找出串的一個子串 |
Lower() | 將串轉換爲小寫 |
LTrim() | 去掉串左邊的空格 |
Right() | 返回串右邊的字符 |
RTrim() | 去掉串右邊的空格 |
Soundex() | 返回串的SOUNDEX值 |
SubString() | 返回子串的字符 |
Upper() | 將串轉換爲大寫 |
11.2.2 日期和時間處理函數
函 數 | 說 明 |
---|---|
AddDate() | 增加一個日期(天、周等) |
AddTime() | 增加一個時間(時、分等) |
CurDate() | 返回當前日期 |
CurTime() | 返回當前時間 |
Date() | 返回日期時間的日期部分 |
DateDiff() | 計算兩個日期之差 |
Date_Add() | 高度靈活的日期運算函數 |
Date_Format() | 返回一個格式化的日期或時間串 |
Day() | 返回一個日期的天數部分 |
DayOfWeek() | 對於一個日期,返回對應的星期幾 |
Hour() | 返回一個時間的小時部分 |
Minute() | 返回一個時間的分鐘部分 |
Month() | 返回一個日期的月份部分 |
Now() | 返回當前日期和時間 |
Second() | 返回一個時間的秒部分 |
Time() | 返回一個日期時間的時間部分 |
Year() | 返回一個日期的年份部分 |
首先需要注意的是MySQL使用的日期格式。無論你什麼時候指定一個日期,不管是插入或更新表值還是用WHERE子句進行過濾,日期必須爲格式yyyy-mm-dd
。因此, 2005年9月1日,給出爲2005-09-01。雖然其他的日期格式可能也行,但這是首選的日期格式,因爲它排除了多義性。
mysql> SELECT cust_id, order_num FROM orders WHERE order_date = '2005-09-01';
+---------+-----------+
| cust_id | order_num |
+---------+-----------+
| 10001 | 20005 |
+---------+-----------+
- 分析:此
SELECT
語句正常運行。它檢索出一個訂單記錄,該訂單記錄的order_date
爲2005-09-01
。
Date(order_date)
指示MySQL僅提取列的日期部分,更可靠的SELECT
語句爲:
mysql> SELECT cust_id, order_num FROM orders WHERE Date(order_date) = '2005-09-01';
+---------+-----------+
| cust_id | order_num |
+---------+-----------+
| 10001 | 20005 |
+---------+-----------+
如果要的是日期,請使用Date():如果你想要的僅是日期,則使用
Date()
是一個良好的習慣,即使你知道相應的列只包含日期也是如此。這樣,如果由於某種原因表中以後有日期和時間值,你的SQL代碼也不用改變。當然,也存在一個Time()
函數,在你只想要時間時應該使用它。
如果你想檢索出2005年9月下的所有訂單,怎麼辦?簡單的相等測試不行,因爲它也要匹配月份中的天數。有幾種解決辦法,其中之一如下所示:
mysql> SELECT cust_id, order_num FROM orders WHERE Date(order_date) BETWEEN '2005-09-01' AND '2005-09-30';
+---------+-----------+
| cust_id | order_num |
+---------+-----------+
| 10001 | 20005 |
| 10003 | 20006 |
| 10004 | 20007 |
+---------+-----------+
- 分析:其中,
BETWEEN
操作符用來把2005-09-01和2005-09-30定義爲一個要匹配的日期範圍。
還有另外一種辦法(一種不需要記住每個月中有多少天或不需要操心閏年2月的辦法):
mysql> SELECT cust_id, order_num FROM orders WHERE Year(order_date)=2005 AND Month(order_date)=9;
+---------+-----------+
| cust_id | order_num |
+---------+-----------+
| 10001 | 20005 |
| 10003 | 20006 |
| 10004 | 20007 |
+---------+-----------+
- 分析:
Year()
是一個從日期(或日期時間)中返回年份的函數。類似,Month()
從日期中返回月份。因此,WHERE Year(order_date)= 2005 AND Month(order_date) = 9
檢索出order_date
爲2005年9月的所有行。
11.2.3 數值處理函數
函 數 | 說 明 |
---|---|
Abs() | 返回一個數的絕對值 |
Cos() | 返回一個角度的餘弦 |
Exp() | 返回一個數的指數值 |
Mod() | 返回除操作的餘數 |
Pi() | 返回圓周率 |
Rand() | 返回一個隨機數 |
Sin() | 返回一個角度的正弦 |
Sqrt() | 返回一個數的平方根 |
Tan() | 返回一個角度的正切 |