### 第12章:函數和操作符
** 目錄**
[ 12.1. 操作符](#)[ 12.1.1. 操作符優先級](#)[ 12.1.2. 圓括號](#)[ 12.1.3. 比較函數和操作符](#)[ 12.1.4. 邏輯操作符](#)[ 12.2. 控制流程函數](#)[ 12.3. 字符串函數](#)[ 12.3.1. 字符串比較函數](#)[ 12.4. 數值函數](#)[ 12.4.1. 算術操作符](#)[ 12.4.2. 數學函數](#)[ 12.5. 日期和時間函數](#)[ 12.6. MySQL使用什么日歷?](#)[ 12.7. 全文搜索功能](#)[ 12.7.1. 布爾全文搜索](#)[ 12.7.2. 全文搜索帶查詢擴展](#)[ 12.7.3. 全文停止字](#)[ 12.7.4. 全文限定條件](#)[ 12.7.5. 微調MySQL全文搜索](#)[ 12.8. Cast函數和操作符](#)[ 12.9. 其他函數](#)[ 12.9.1. 位函數](#)[ 12.9.2. 加密函數](#)[ 12.9.3. 信息函數](#)[ 12.9.4. 其他函數](#)[ 12.10. 與GROUP BY子句同時使用的函數和修改程序``](#)[12.10.1. GROUP BY(聚合)函數](#)[12.10.2. GROUP BY修改程序](#)[12.10.3. 具有隱含字段的GROUP BY](#)
在SQL 語句中,表達式可用于一些諸如SELECT語句的ORDER BY 或HAVING子句、SELECT、 DELETE或 UPDATE語句的WHERE 子句或 SET語句之類的地方。使用文本值、column值、NULL值、函數、 操作符來書寫表達式。 本章敘述了可用于書寫MySQL表達式的函數和操作符。
除非在文檔編制中對一個函數或操作符另有指定的情況外,一個包含NULL 的表達式通常產生一個NULL 值。
**注釋**:在默認狀態下, 在函數和緊隨其后的括號之間不得存在空格。這能幫助? MySQL 分析程序區分一些同函數名相同的函數調用以及表或列。不過,函數自變量周圍允許有空格出現。
可以通過選擇--sql-mode=IGNORE_SPACE來打開MySQL服務器的方法使服務器接受函數名后的空格。 個人客戶端程序可通過選擇mysql_real_connect()的CLIENT_IGNORE_SPACE 實現這一狀態。在以上兩種情況中, 所有的函數名都成為保留字。請參見[5.3.2節,“SQL服務器模式”](# "5.3.2.?The Server SQL Mode").?
為節省時間,本章中對大多數例子使用簡寫形式展示了 **mysql**程序的輸出結果。 對于以下格式的舉例展示:
mysql> **SELECT MOD(29,9);**
+-----------+
| mod(29,9) |
+-----------+
|???????? 2 |
+-----------+
1 rows in set (0.00 秒)
使用如下格式進行代替:
mysql> **SELECT MOD(29,9);**
??????? -> 2
### 12.1.?操作符
[ 12.1.1. 操作符優先級](#)[ 12.1.2. 圓括號](#)[ 12.1.3. 比較函數和操作符](#)[ 12.1.4. 邏輯操作符](#)
### 12.1.1.?操作符優先級
以下列表顯示了操作符優先級的由低到高的順序。排列在同一行的操作符具有相同的優先級。
:=
||, OR, XOR
&&, AND
NOT
BETWEEN, CASE, WHEN, THEN, ELSE
=, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
|
&
<<, >>
-, +
*, /, DIV, %, MOD
^
- (一元減號), ~ (一元比特反轉)
!
BINARY, COLLATE
**注釋**:假如 HIGH_NOT_PRECEDENCE SQL 模式被激活,則 NOT 的優先級同 the? ! 操作符相同。請參見[5.3.2節,“SQL服務器模式”](# "5.3.2.?The Server SQL Mode")。
### 12.1.2.?圓括號
-
( ... )
使用括弧來規定表達式的運算順序,例如:
~~~
mysql> SELECT 1+2*3;
-> 7
mysql> SELECT (1+2)*3;
-> 9
~~~
### 12.1.3.?比較函數和操作符
比較運算產生的結果為1(TRUE)、0 (FALSE)或 NULL。這些運算可用于數字和字符串。根據需要,字符串可自動轉換為數字,而數字也可自動轉換為字符串。
本章中的一些函數 (如LEAST()和GREATEST()) 的所得值不包括 1 (TRUE)、 0 (FALSE)和 NULL。然而,其所得值乃是基于按照下述規則運行的比較運算:??
MySQL按照以下規則進行數值比較:
- 若有一個或兩個參數為 NULL,除非NULL-safe <=> 等算符,則比較運算的結果為NULL。
- 若同一個比較運算中的兩個參數都是字符串,則按照字符串進行比較。
- 若兩個參數均為整數,則按照整數進行比較。?
- 十六進制值在不需要作為數字進行比較時,則按照二進制字符串進行處理。
- 假如參數中的一個為 TIMESTAMP 或 DATETIME 列,而其它參數均為常數, 則在進行比較前將常數轉為 timestamp。這樣做的目的是為了使ODBC的進行更加順利。注意,這不適合IN()中的參數!為了更加可靠,在進行對比時通常使用完整的 datetime/date/time字符串。
- 在其它情況下,參數作為浮點數進行比較。??
在默認狀態下,字符串比較不區分大小寫,并使用現有字符集(默認為cp1252 Latin1,同時對英語也適合)。
為了進行比較,可使用CAST()函數將某個值轉為另外一種類型。 使用CONVERT()將字符串值轉為不同的字符集。請參見[12.8節,“Cast函數和操作符”](# "12.8.?Cast Functions and Operators")。
以下例子說明了比較運算中將字符串轉為數字的過程:
mysql> ** SELECT 1 > '6x';**
??????? -> 0
mysql> ** SELECT 7 > '6x';**
??????? -> 1
mysql> ** SELECT 0 > 'x6';**
??????? -> 0
mysql> ** SELECT 0 = 'x6';**
??????? -> 1
注意,在將一個字符串列同一個數字進行比較時, MySQL 不能使用列中的索引進行快速查找。假如*str_col*是一個編入索引的字符串列,則在以下語句中,索引不能執行查找功能:
SELECT * FROM *tbl_name* WHERE *str_col*=1;
其原因是許多不同的字符串都可被轉換為數值 1: '1'、 ' 1'、 '1a'、 ……
- =
等于:
mysql> ** SELECT 1 = 0;**
??????? -> 0
mysql> ** SELECT '0' = 0;**
??????? -> 1
mysql> ** SELECT '0.0' = 0;**
??????? -> 1
mysql> ** SELECT '0.01' = 0;**
??????? -> 0
mysql> ** SELECT '.01' = 0.01;**
??????? -> 1
- <=>
NULL-safe equal.這個操作符和=操作符執行相同的比較操作,不過在兩個操作碼均為NULL時,其所得值為1而不為NULL,而當一個操作碼為NULL時,其所得值為0而不為NULL。
mysql> ** SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;**
??????? -> 1, 1, 0
mysql> ** SELECT 1 = 1, NULL = NULL, 1 = NULL;**
??????? -> 1, NULL, NULL
- <> !=
不等于:
mysql> ** SELECT '.01' <> '0.01';**
??????? -> 1
mysql> ** SELECT .01 <> '0.01';**
??????? -> 0
mysql> ** SELECT 'zapp' <> 'zappp';**
??????? -> 1
- <=
小于或等于:
mysql> ** SELECT 0.1 <= 2;**
??????? -> 1
- <
小于:
mysql> ** SELECT 2 < 2;**
??????? -> 0
- >=
大于或等于:
mysql> ** SELECT 2 >= 2;**
??????? -> 1
- >
大于:
mysql> ** SELECT 2 > 2;**
??????? -> 0
- IS * boolean_value* IS NOT *boolean_value*
根據一個布爾值來檢驗一個值,在這里,布爾值可以是TRUE、FALSE或UNKNOWN。
mysql> ** SELECT 1 IS TRUE, 0 IS FALSE, NULL IS UNKNOWN;**
??????? -> 1, 1, 1
mysql> ** SELECT 1 IS NOT UNKNOWN, 0 IS NOT UNKNOWN, NULL IS NOT UNKNOWN;**
??????? -> 1, 1, 0
- IS NULL IS NOT NULL
檢驗一個值是否為 NULL。
mysql> ** SELECT 1 IS NULL, 0 IS NULL, NULL IS NULL;**
??????? -> 0, 0, 1
mysql> ** SELECT 1 IS NOT NULL, 0 IS NOT NULL, NULL IS NOT NULL;**
??????? -> 1, 1, 0
為了能夠順利的使用ODBC 程序工作,在使用IS NULL時,MySQL支持一下額外特性:
- 在一個值產生后,立即運行一個以下格式的語句,從而找到最新AUTO_INCREMENT 值的所在行:
o???????????????????? SELECT * FROM *tbl_name* WHERE *auto_col* IS NULL
當設置SQL_AUTO_IS_NULL=0時,這項操作無法運行。請參見[13.5.3節,“SET語法”](# "13.5.3.?SET Syntax")。
- 對于命名為NOT NULL 的DATE 和DATETIME列,可通過使用如下的 語句找到特定日期 '0000-00-00':
o???????????????????? SELECT * FROM *tbl_name* WHERE *date_column* IS NULL
運行這一步需要使用一些 ODBC 應用軟件,因為 ODBC本身不支持 一個 '0000-00-00'的時間值。?
- *expr* BETWEEN *min* AND *max*
假如*expr大于或等于**min*且*expr*小于或等于*max*, 則BETWEEN 的返回值為1,或是0。若所有參數都是同一類型,則上述關系相當于表達式?? (*min* <= *expr* AND *expr* <= *max*)。其它類型的轉換根據本章開篇所述規律進行,且適用于3種參數中任意一種。?
mysql> ** SELECT 1 BETWEEN 2 AND 3;**
??????? -> 0
mysql> ** SELECT 'b' BETWEEN 'a' AND 'c';**
??????? -> 1
mysql> ** SELECT 2 BETWEEN 2 AND '3';**
??????? -> 1
mysql> ** SELECT 2 BETWEEN 2 AND 'x-3';**
??????? -> 0
- *expr* NOT BETWEEN *min* AND *max*
這相當于NOT(*expr* BETWEEN *min* AND *max*)。
·???????? COALESCE(*value*,...)
返回值為列表當中的第一個非 NULL值,在沒有非NULL 值得情況下返回值為 NULL 。
mysql> ** SELECT COALESCE(NULL,1);**
??????? -> 1
mysql> ** SELECT COALESCE(NULL,NULL,NULL);**
??????? -> NULL
·???????? GREATEST(*value1*,*value2*,...)
當有2或多個參數時,返回值為最大(最大值的)參數。比較參數所依據的規律同LEAST()相同。
mysql> ** SELECT GREATEST(2,0);**
??????? -> 2
mysql> ** SELECT GREATEST(34.0,3.0,5.0,767.0);**
??????? -> 767.0
mysql> ** SELECT GREATEST('B','A','C');**
??????? -> 'C'
在沒有自變量為NULL的情況下,GREATEST()的返回值為NULL。
·???????? *expr* IN (*value*,...)
- 若*expr*為IN列表中的任意一個值,則其返回值為 1 , 否則返回值為0。假如所有的值都是常數,則其計算和分類根據 *expr* 的類型進行。這時,使用二分搜索來搜索信息。如IN值列表全部由常數組成,則意味著IN 的速度非常之快。如*expr*是一個區分大小寫的字符串表達式,則字符串比較也按照區分大小寫的方式進行。?
mysql> ** SELECT 2 IN (0,3,5,'wefwf');**
??????? -> 0
mysql> ** SELECT 'wefwf' IN (0,3,5,'wefwf');**
??????? -> 1
IN 列表中所列值的個數僅受限于 max_allowed_packet 值。
為了同SQL 標準相一致,在左側表達式為NULL的情況下,或是表中找不到匹配項或是表中一個表達式為NULL 的情況下,IN的返回值均為NULL。
IN() 語構也可用書寫某些類型的子查詢。請參見[13.2.8.3節,“使用ANY、IN和SOME進行子查詢”](# "13.2.8.3.?Subqueries with ANY, IN, and SOME")。
·???????? *expr* NOT IN (*value*,...)
這與NOT (*expr* IN (*value*,...))相同。
- ISNULL(*expr*)
如*expr*為NULL,那么ISNULL() 的返回值為 1,否則返回值為 0。
mysql> ** SELECT ISNULL(1+1);**
??????? -> 0
mysql> ** SELECT ISNULL(1/0);**
??????? -> 1
使用= 的NULL 值對比通常是錯誤的。
?ISNULL() 函數同 IS NULL比較操作符具有一些相同的特性。請參見有關IS NULL 的說明。
·???????? INTERVAL(*N*,*N1*,*N2*,*N3*,...)
假如*N* < *N1**,*則返回值為0;假如*N* < *N2*等等,則返回值為1;假如*N*為NULL,則返回值為 -1 。所有的參數均按照整數處理。為了這個函數的正確運行,必須滿足 *N1* < *N2* < *N3* < ……< *Nn*。其原因是使用了二分查找(極快速)。
mysql> ** SELECT INTERVAL(23, 1, 15, 17, 30, 44, 200);**
??????? -> 3
mysql> ** SELECT INTERVAL(10, 1, 10, 100, 1000);**
??????? -> 2
mysql> ** SELECT INTERVAL(22, 23, 30, 44, 200);**
??????? -> 0
·???????? LEAST(*value1*,*value2*,...)
在有兩個或多個參數的情況下, 返回值為最小 (最小值)參數。用一下規則將自變量進行對比:
- 假如返回值被用在一個 INTEGER 語境中,或是所有參數均為整數值,則將其作為整數值進行比較。
- 假如返回值被用在一個 REAL語境中,或所有參數均為實值,則 將其作為實值進行比較。
- 假如任意一個參數是一個區分大小寫的字符串,則將參數按照區分大小寫的字符串進行比較。
- 在其它情況下,將參數作為區分大小寫的字符串進行比較。
假如任意一個自變量為NULL,則 LEAST()的返回值為NULL 。
mysql> ** SELECT LEAST(2,0);**
??????? -> 0
mysql> ** SELECT LEAST(34.0,3.0,5.0,767.0);**
??????? -> 3.0
mysql> ** SELECT LEAST('B','A','C');**
??????? -> 'A'
注意,上面的轉換規則在一些邊界情形中會產生一些奇特的結果:??
mysql> ** SELECT CAST(LEAST(3600, 9223372036854775808.0) as SIGNED);**
??????? -> -9223372036854775808
發生這種情況的原因是MySQL在整數語境中讀取9223372036854775808.0。整數表示法不利于保存數值,因此它包括一個帶符號整數。
### 12.1.4.?邏輯操作符
在SQL中,所有邏輯 操作符的求值所得結果均為 TRUE、FALSE或 NULL (UNKNOWN)。在 MySQL中,它們體現為? 1 (TRUE)、 0 (FALSE)和 NULL。其大多數都與不同的數據庫SQL通用,然而一些服務器對TRUE的返回值可能是任意一個非零值。
- NOT !
邏輯 NOT。當操作數為0 時,所得值為 1 ;當操作數為非零值時,所得值為? 0 ,而當操作數為NOT NULL時,所得的返回值為 NULL。
mysql> ** SELECT NOT 10;**
??????? -> 0
mysql> ** SELECT NOT 0;**
??????? -> 1
mysql> ** SELECT NOT NULL;**
??????? -> NULL
mysql> ** SELECT ! (1+1);**
? ??????-> 0
mysql> ** SELECT ! 1+1;**
??????? -> 1
最后一個例子產生的結果為 1,原因是表達式的計算方式和(!1)+1相同。
- AND &&
邏輯AND。當所有操作數均為非零值、并且不為NULL時,計算所得結果為? 1 ,當一個或多個操作數為0 時,所得結果為 0 ,其余情況返回值為 NULL 。
mysql> ** SELECT 1 && 1;**
??????? -> 1
mysql> ** SELECT 1 && 0;**
??????? -> 0
mysql> ** SELECT 1 && NULL;**
??????? -> NULL
mysql> ** SELECT 0 && NULL;**
??????? -> 0
mysql> ** SELECT NULL && 0;**
??????? -> 0
- OR ||
邏輯 OR。當兩個操作數均為非 NULL值時,如有任意一個操作數為非零值,則結果為1,否則結果為0。當有一個操作數為NULL時,如另一個操作數為非零值,則結果為1,否則結果為 NULL 。假如兩個操作數均為? NULL,則所得結果為 NULL。
mysql> ** SELECT 1 || 1;**
??? ????-> 1
mysql> ** SELECT 1 || 0;**
??????? -> 1
mysql> ** SELECT 0 || 0;**
??????? -> 0
mysql> ** SELECT 0 || NULL;**
??????? -> NULL
mysql> ** SELECT 1 || NULL;**
??????? -> 1
- XOR
邏輯XOR。當任意一個操作數為 NULL時,返回值為NULL。對于非?? NULL 的操作數,假如一個奇數操作數為非零值,則計算所得結果為? 1 ,否則為? 0 。
mysql> ** SELECT 1 XOR 1;**
??????? -> 0
mysql> ** SELECT 1 XOR 0;**
??????? -> 1
mysql> ** SELECT 1 XOR NULL;**
??????? -> NULL
mysql> ** SELECT 1 XOR 1 XOR 1;**
??????? -> 1
a XOR b 的計算等同于? (a AND (NOT b)) OR ((NOT a)和 b)。
同樣見 [ 12.1.1節,“操作符優先級”](# "12.1.1.?Operator Precedence")。
### 12.2.?控制流程函數
- CASE * value* WHEN [*compare-value*] THEN *result* [WHEN [*compare-value*] THEN *result* ...] [ELSE *result*] END CASE WHEN [*condition*] THEN *result* [WHEN [*condition*] THEN *result* ...] [ELSE *result*] END
在第一個方案的返回結果中, *value*=*compare-value*。而第二個方案的返回結果是第一種情況的真實結果。如果沒有匹配的結果值,則返回結果為ELSE后的結果,如果沒有ELSE 部分,則返回值為 NULL。
mysql> ** SELECT CASE 1 WHEN 1 THEN 'one'**
??? ->???? ** WHEN 2 THEN 'two' ELSE 'more' END;**
??????? -> 'one'
mysql> ** SELECT CASE WHEN 1>0 THEN 'true' ELSE 'false' END;**
??????? -> 'true'
mysql> ** SELECT CASE BINARY 'B'**
??? ->???? ** WHEN 'a' THEN 1 WHEN 'b' THEN 2 END;**
??????? -> NULL
一個CASE表達式的默認返回值類型是任何返回值的相容集合類型,但具體情況視其所在語境而定。如果用在字符串語境中,則返回結果味字符串。如果用在數字語境中,則返回結果為十進制值、實值或整數值。?
- IF(*expr1*,*expr2*,*expr3*)
如果 * expr1*是TRUE (*expr1* <> 0 and *expr1* <> NULL),則 IF()的返回值為*expr2*; 否則返回值則為 *expr3*。IF() 的返回值為數字值或字符串值,具體情況視其所在語境而定。
mysql> ** SELECT IF(1>2,2,3);**
??????? -> 3
mysql> ** SELECT IF(1<2,'yes ','no');**
????? ??-> 'yes'
mysql> ** SELECT IF(STRCMP('test','test1'),'no','yes');**
??????? -> 'no'
如果*expr2*或*expr3*中只有一個明確是 NULL,則IF() 函數的結果類型 為非NULL表達式的結果類型。
*expr1* 作為一個整數值進行計算,就是說,假如你正在驗證浮點值或字符串值,?? 那么應該使用比較運算進行檢驗。
mysql> ** SELECT IF(0.1,1,0);**
??????? -> 0
mysql> ** SELECT IF(0.1<>0,1,0);**
??????? -> 1
在所示的第一個例子中,IF(0.1)的返回值為0,原因是 0.1 被轉化為整數值,從而引起一個對 IF(0)的檢驗。這或許不是你想要的情況。在第二個例子中,比較檢驗了原始浮點值,目的是為了了解是否其為非零值。比較結果使用整數。
IF() (這一點在其被儲存到臨時表時很重要 ) 的默認返回值類型按照以下方式計算:
<table border="1" cellpadding="0" id="table1"><tr><td> <p><b> <span>表達式</span></b></p></td> <td> <p><b> <span>返回值</span></b></p></td> </tr><tr><td> <p><i> <span> expr2</span></i><span> </span><span>或<i><span>expr3</span></i><span> </span>返回值為一個字符串。</span></p></td> <td> <p> <span>字符串</span></p></td> </tr><tr><td> <p><i> <span> expr2</span></i><span> </span><span>或<i><span>expr3</span></i><span> </span>返回值為一個浮點值。</span></p></td> <td> <p> <span>浮點</span></p></td> </tr><tr><td> <p><i> <span> expr2</span></i><span> </span><span>或 <i> <span>expr3</span></i><span> </span> 返回值為一個整數。<span>? </span></span></p></td> <td> <p> <span>整數</span></p></td> </tr></table>
假如*expr2*和*expr3* 都是字符串,且其中任何一個字符串區分大小寫,則返回結果是區分大小寫。
- IFNULL(*expr1*,*expr2*)
假如*expr1*不為 NULL,則 IFNULL() 的返回值為 *expr1*; 否則其返回值為 *expr2*。IFNULL()的返回值是數字或是字符串,具體情況取決于其所使用的語境。
mysql> **SELECT IFNULL(1,0);**
??????? -> 1
mysql> **SELECT IFNULL(NULL,10);**
??????? -> 10
mysql> **SELECT IFNULL(1/0,10);**
??????? -> 10
mysql> **SELECT IFNULL(1/0,'yes');**
??????? -> 'yes'
IFNULL(*expr1*,*expr2*)的默認結果值為兩個表達式中更加“通用”的一個,順序為STRING、 REAL或 INTEGER。假設一個基于表達式的表的情況,? 或MySQL必須在內存儲器中儲存一個臨時表中IFNULL()的返回值:
CREATE TABLE tmp SELECT IFNULL(1,'test') AS test;
在這個例子中,測試列的類型為 CHAR(4)。
- NULLIF(*expr1*,*expr2*)
如果*expr1* = *expr2*? 成立,那么返回值為NULL,否則返回值為 *expr1*。這和CASE WHEN *expr1* = *expr2* THEN NULL ELSE *expr1* END相同。
mysql> **SELECT NULLIF(1,1);**
??????? -> NULL
mysql> **SELECT NULLIF(1,2);**
??????? -> 1
注意,如果參數不相等,則 MySQL 兩次求得的值為? expr1 。
### 12.3.?字符串函數
[ 12.3.1. 字符串比較函數](#)
假如結果的長度大于 max_allowed_packet 系統變量的最大值時,字符串值函數的返回值為NULL。請參見[7.5.2節,“調節服務器參數”](# "7.5.2.?Tuning Server Parameters")。
對于在字符串位置操作的函數,第一個位置的編號為 1。
- ASCII(*str*)
返回值為字符串*str*的最左字符的數值。假如*str*為空字符串,則返回值為 0 。假如*str*為NULL,則返回值為 NULL。 ASCII()用于帶有從 0到255的數值的字符。
mysql> **SELECT ASCII('2');**
??????? -> 50
mysql> **SELECT ASCII(2);**
??????? -> 50
mysql> **SELECT ASCII('dx');**
??????? -> 100
見 ORD()函數。
- BIN(*N*)
返回值為*N*的二進制值的字符串表示,其中? *N*為一個longlong (BIGINT) 數字。這等同于 CONV(*N*,10,2)。假如*N*為NULL,則返回值為 NULL。
mysql> **SELECT BIN(12);**
??????? -> '1100'
- BIT_LENGTH(*str*)
返回值為二進制的字符串*str *長度。
mysql> **SELECT BIT_LENGTH('text');**
??????? -> 32
- CHAR(*N*,... [USING *charset*])
CHAR()將每個參數*N*理解為一個整數,其返回值為一個包含這些整數的代碼值所給出的字符的字符串。NULL值被省略。
mysql> **SELECT CHAR(77,121,83,81,'76');**
??????? -> 'MySQL'
mysql> **SELECT CHAR(77,77.3,'77.3');**
??????? -> 'MMM'
大于 255的CHAR()參數被轉換為多結果字符。 例如,CHAR(256) 相當于 CHAR(1,0), 而CHAR(256*256) 則相當于 CHAR(1,0,0):
mysql> **SELECT HEX(CHAR(1,0)), HEX(CHAR(256));**
+----------------+----------------+
| HEX(CHAR(1,0)) | HEX(CHAR(256)) |
+----------------+----------------+
| 0100?????????? | 0100?????????? |
+----------------+----------------+
mysql> **SELECT HEX(CHAR(1,0,0)), HEX(CHAR(256*256));**
+------------------+--------------------+
| HEX(CHAR(1,0,0)) | HEX(CHAR(256*256)) |
+------------------+--------------------+
| 010000?????????? | 010000???????????? |
+------------------+--------------------+
CHAR()的返回值為一個二進制字符串。可選擇使用USING語句產生一個給出的字符集中的字符串:
mysql> **SELECT CHARSET(CHAR(0x65)), CHARSET(CHAR(0x65 USING utf8));**
~~~
mysql> SELECT CHARSET(CHAR(0x65)), CHARSET(CHAR(0x65 USING utf8));
~~~
~~~
+---------------------+--------------------------------+
~~~
~~~
| CHARSET(CHAR(0x65)) | CHARSET(CHAR(0x65 USING utf8)) |
~~~
~~~
+---------------------+--------------------------------+
~~~
~~~
| binary????????????? | utf8?????????????????????????? |
~~~
~~~
+---------------------+--------------------------------+
~~~
如果 USING已經產生,而結果字符串不符合給出的字符集,則會發出警告。?? 同樣,如果嚴格的SQL模式被激活,則CHAR()的結果會成為 NULL。
- CHAR_LENGTH(*str*)
返回值為字符串*str* 的長度,長度的單位為字符。一個多字節字符算作一個單字符。*對于一個*包含五個二字節字符集, LENGTH()返回值為 10, 而CHAR_LENGTH()的返回值為5。
- CHARACTER_LENGTH(*str*)
CHARACTER_LENGTH()是CHAR_LENGTH()的同義詞。
- COMPRESS(*string_to_compress*)
壓縮一個字符串。這個函數要求 MySQL已經用一個諸如zlib的壓縮庫壓縮過。?? 否則,返回值始終是NULL。UNCOMPRESS() 可將壓縮過的字符串進行解壓縮。
mysql> **SELECT LENGTH(COMPRESS(REPEAT('a',1000)));**
?????? ?-> 21
mysql> **SELECT LENGTH(COMPRESS(''));**
??????? -> 0
mysql> **SELECT LENGTH(COMPRESS('a'));**
??????? -> 13
mysql> **SELECT LENGTH(COMPRESS(REPEAT('a',16)));**
??????? -> 15
壓縮后的字符串的內容按照以下方式存儲:
- 空字符串按照空字符串存儲。
- 非空字符串未壓縮字符串的四字節長度進行存儲(首先為低字節),后面是壓縮字符串。如果字符串以空格結尾,就會在后加一個"."號,以防止當結果值是存儲在CHAR或VARCHAR類型的字段列時,出現自動把結尾空格去掉的現象。(不推薦使用 CHAR 或VARCHAR 來存儲壓縮字符串。最好使用一個 BLOB 列代替)。
- CONCAT(*str1*,*str2*,...)???????????????????????
返回結果為連接參數產生的字符串。如有任何一個參數為NULL ,則返回值為 NULL。或許有一個或多個參數。 如果所有參數均為非二進制字符串,則結果為非二進制字符串。 如果自變量中含有任一二進制字符串,則結果為一個二進制字符串。一個數字參數被轉化為與之相等的二進制字符串格式;若要避免這種情況,可使用顯式類型 cast, 例如: SELECT CONCAT(CAST(int_col AS CHAR), char_col)
mysql> **SELECT CONCAT('My', 'S', 'QL');**
??????? -> 'MySQL'
mysql> **SELECT CONCAT('My', NULL, 'QL');**
??????? -> NULL
mysql> **SELECT CONCAT(14.3);**
??????? -> '14.3'
- CONCAT_WS(*separator*,*str1*,*str2*,...)
CONCAT_WS() 代表 CONCAT With Separator ,是CONCAT()的特殊形式。?? 第一個參數是其它參數的分隔符。分隔符的位置放在要連接的兩個字符串之間。分隔符可以是一個字符串,也可以是其它參數。如果分隔符為 NULL,則結果為 NULL。函數會忽略任何分隔符參數后的 NULL 值。
mysql> **SELECT CONCAT_WS(',','First name','Second name','Last Name');**
??????? -> 'First name,Second name,Last Name'
mysql> **SELECT CONCAT_WS(',','First name',NULL,'Last Name');**
??????? -> 'First name,Last Name'
CONCAT_WS()不會忽略任何空字符串。 (然而會忽略所有的 NULL)。
- CONV(*N*,*from_base*,*to_base*)
不同數基間轉換數字。返回值為數字的*N*字符串表示,由*from_base*基轉化為 *to_base *基。如有任意一個參數為NULL,則返回值為 NULL。自變量 *N* 被理解為一個整數,但是可以被指定為一個整數或字符串。最小基數為 2 ,而最大基數則為 36。 If *to_base*是一個負數,則 *N*被看作一個帶符號數。否則, *N*被看作無符號數。 CONV() 的運行精確度為 64比特。
mysql> **SELECT CONV('a',16,2);**
??????? -> '1010'
mysql> **SELECT CONV('6E',18,8);**
??????? -> '172'
mysql> **SELECT CONV(-17,10,-18);**
??????? -> '-H'
mysql> **SELECT CONV(10+'10'+'10'+0xa,10,10);**
??????? -> '40'
- ELT(*N*,*str1*,*str2*,*str3*,...)
若*N* = 1,則返回值為? *str1*,若*N* = 2,則返回值為 *str2*,以此類推。?? 若*N*小于1或大于參數的數目,則返回值為 NULL 。 ELT() 是? FIELD()的補數。
mysql> **SELECT ELT(1, 'ej', 'Heja', 'hej', 'foo');**
??????? -> 'ej'
mysql> **SELECT ELT(4, 'ej', 'Heja', 'hej', 'foo');**
??????? -> 'foo'
- EXPORT_SET(*bits*,*on*,*off*[,*separator*[,*number_of_bits*]])
返回值為一個字符串,其中對于*bits*值中的每個位組,可以得到一個 *on* 字符串,而對于每個清零比特位,可以得到一個*off*字符串。*bits* 中的比特值按照從右到左的順序接受檢驗 (由低位比特到高位比特)。字符串被分隔字符串分開(默認為逗號‘,’),按照從左到右的順序被添加到結果中。*number_of_bits*會給出被檢驗的二進制位數 (默認為 64)。
mysql> **SELECT EXPORT_SET(5,'Y','N',',',4);**
??????? -> 'Y,N,Y,N'
mysql> **SELECT EXPORT_SET(6,'1','0',',',10);**
???? ???-> '0,1,1,0,0,0,0,0,0,0'
- FIELD(*str*,*str1*,*str2*,*str3*,...)
返回值為*str1*, *str2*, *str3*,……列表中的*str*指數。在找不到*str* 的情況下,返回值為 0 。
如果所有對于FIELD() 的參數均為字符串,則所有參數均按照字符串進行比較。如果所有的參數均為數字,則按照數字進行比較。否則,參數按照雙倍進行比較。
如果*str*為NULL,則返回值為0 ,原因是NULL不能同任何值進行同等比較。FIELD() 是ELT()的補數。
mysql> **SELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo');**
??????? -> 2
mysql> **SELECT FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo');**
??????? -> 0
- FIND_IN_SET(*str*,*strlist*)
假如字符串*str*在由*N* 子鏈組成的字符串列表*strlist* 中, 則返回值的范圍在 1 到 *N*之間 。一個字符串列表就是一個由一些被‘,’符號分開的自鏈組成的字符串。如果第一個參數是一個常數字符串,而第二個是type SET列,則?? FIND_IN_SET() 函數被優化,使用比特計算。如果*str*不在*strlist*或*strlist* 為空字符串,則返回值為 0 。如任意一個參數為NULL,則返回值為 NULL。 這個函數在第一個參數包含一個逗號(‘,’)時將無法正常運行。?
mysql> **SELECT FIND_IN_SET('b','a,b,c,d');**
??????? -> 2
- FORMAT(*X*,*D*)
將number *X*設置為格式 '#,###,###.##', 以四舍五入的方式保留到小數點后*D*位, 而返回結果為一個字符串。詳見[12.9.4節,“其他函數”](# "12.9.4.?Miscellaneous Functions").
- HEX(*N_or_S*)
如果*N_OR_S*是一個數字,則返回一個 十六進制值 *N 的*字符串表示,在這里,?? *N*是一個longlong (BIGINT)數。這相當于 CONV(N,10,16)。
如果*N_OR_S*是一個字符串,則返回值為一個*N_OR_S*的十六進制字符串表示, 其中每個*N_OR_S* 里的每個字符被轉化為兩個十六進制數字。
mysql> **SELECT HEX(255);**
??????? -> 'FF'
mysql> **SELECT 0x616263;**
??????? -> 'abc'
mysql> **SELECT HEX('abc');**
??????? -> 616263
- INSERT(*str*,*pos*,*len*,*newstr*)
返回字符串 *str*, 其子字符串起始于 *pos*位置和長期被字符串 *newstr*取代的*len*字符。? 如果*pos*超過字符串長度,則返回值為原始字符串。 假如*len*的長度大于其它字符串的長度,則從位置*pos*開始替換。若任何一個參數為null,則返回值為NULL。
mysql> **SELECT INSERT('Quadratic', 3, 4, 'What');**
??????? -> 'QuWhattic'
mysql> **SELECT INSERT('Quadratic', -1, 4, 'What');**
??????? -> 'Quadratic'
mysql> **SELECT INSERT('Quadratic', 3, 100, 'What');**
??????? -> 'QuWhat'
這個函數支持多字節字元。
- INSTR(*str*,*substr*)
返回字符串 *str*中子字符串的第一個出現位置。這和LOCATE()的雙參數形式相同,除非參數的順序被顛倒。?
mysql> **SELECT INSTR('foobarbar', 'bar');**
??????? -> 4
mysql> **SELECT INSTR('xbar', 'foobar');**
??????? -> 0
這個函數支持多字節字元,并且只有當至少有一個參數是二進制字符串時區分大小寫。
- LCASE(*str*)
LCASE() 是 LOWER()的同義詞。
- LEFT(*str*,*len*)
返回從字符串*str*開始的*len*最左字符。
mysql> **SELECT LEFT('foobarbar', 5);**
??????? -> 'fooba'
- LENGTH(*str*)
返回值為字符串*str*的長度,單位為字節。一個多字節字符算作多字節。這意味著 對于一個包含5個2字節字符的字符串, LENGTH() 的返回值為 10, 而 CHAR_LENGTH()的返回值則為5。
mysql> **SELECT LENGTH('text');**
??????? -> 4
- LOAD_FILE(*file_name*)
讀取文件并將這一文件按照字符串的格式返回。 文件的位置必須在服務器上,你必須為文件制定路徑全名,而且你還必須擁有FILE 特許權。文件必須可讀取,文件容量必須小于 max_allowed_packet字節。
若文件不存在,或因不滿足上述條件而不能被讀取, 則函數返回值為 NULL。
mysql> **UPDATE *tbl_name***
?????????? SET *blob_column*=LOAD_FILE('/tmp/picture')
?????????? WHERE id=1;
- LOCATE(*substr*,*str*) , LOCATE(*substr*,*str*,*pos*)
第一個語法返回字符串 *str*中子字符串*substr*的第一個出現位置。第二個語法返回字符串 *str*中子字符串*substr*的第一個出現位置, 起始位置在*pos*。如若*substr*不在*str*中,則返回值為0。
mysql> **SELECT LOCATE('bar', 'foobarbar');**
??????? -> 4
mysql> **SELECT LOCATE('xbar', 'foobar');**
??????? -> 0
mysql> **SELECT LOCATE('bar', 'foobarbar',5);**
??????? -> 7
這個函數支持多字節字元,并且只有當至少有一個參數是二進制字符串時區分大小寫。?
- LOWER(*str*)
返回字符串 *str* 以及所有根據最新的字符集映射表變為小寫字母的字符 (默認為? cp1252 Latin1)。
mysql> **SELECT LOWER('QUADRATICALLY');**
??????? -> 'quadratically'
這個函數支持多字節字元。
- LPAD(*str*,*len*,*padstr*)
返回字符串 *str*, 其左邊由字符串*padstr*填補到*len* 字符長度。假如*str*的長度大于*len*, 則返回值被縮短至 *len* 字符。
mysql> **SELECT LPAD('hi',4,'??');**
??????? -> '??hi'
mysql> **SELECT LPAD('hi',1,'??');**
??????? -> 'h'
- LTRIM(*str*)
返回字符串 *str*,其引導空格字符被刪除。
mysql> **SELECT LTRIM('? barbar');**
??????? -> 'barbar'
這個函數支持多字節字元。
- MAKE_SET(*bits*,*str1*,*str2*,...)
返回一個設定值 (一個包含被‘,’號分開的字字符串的字符串) ,由在*bits* 組中具有相應的比特的字符串組成。*str1*對應比特 0, *str2*對應比特1,以此類推。*str1*, *str2*, ...中的 NULL值不會被添加到結果中。
mysql> **SELECT MAKE_SET(1,'a','b','c');**
??????? -> 'a'
mysql> **SELECT MAKE_SET(1 | 4,'hello','nice','world');**
??????? -> 'hello,world'
mysql> **SELECT MAKE_SET(1 | 4,'hello','nice',NULL,'world');**
??????? -> 'hello'
mysql> **SELECT MAKE_SET(0,'a','b','c');**
??????? -> ''
- MID(*str*,*pos*,*len*)
MID(*str*,*pos*,*len*) 是 SUBSTRING(*str*,*pos*,*len*)的同義詞。
- OCT(*N*)
返回一個 *N*的八進制值的字符串表示,其中 *N*是一個longlong (BIGINT)數。這等同于CONV(N,10,8)。若*N*為 NULL ,則返回值為NULL。
mysql> **SELECT OCT(12);**
??????? -> '14'
- OCTET_LENGTH(*str*)
OCTET_LENGTH() 是 LENGTH()的同義詞。
- ORD(*str*)
若字符串*str*的最左字符是一個多字節字符,則返回該字符的代碼, 代碼的計算通過使用以下公式計算其組成字節的數值而得出:
~~~
?? (1st byte code)
~~~
~~~
+ (2nd byte code × 256)
~~~
~~~
+ (3rd byte code × 2562) ...
~~~
?
假如最左字符不是一個多字節字符,那么 ORD()和函數ASCII()返回相同的值。
mysql> **SELECT ORD('2');**
??????? -> 50
- POSITION(*substr* IN *str*)
POSITION(*substr* IN *str*)是 LOCATE(*substr*,*str*)同義詞。
- QUOTE(*str*)
引證一個字符串,由此產生一個在SQL語句中可用作完全轉義數據值的結果。? 返回的字符串由單引號標注,每例都帶有單引號 (‘'’)、 反斜線符號 (‘\’)、 ASCII NUL以及前面有反斜線符號的Control-Z 。如果自變量的值為NULL, 則返回不帶單引號的單詞 “NULL”。
mysql> **SELECT QUOTE('Don\'t!');**
??????? -> 'Don\'t!'
mysql> **SELECT QUOTE(NULL);**
??????? -> NULL
- REPEAT(*str*,*count*)
返回一個由重復的字符串*str* 組成的字符串,字符串*str*的數目等于*count*。 若 *count* <= 0,則返回一個空字符串。若*str*或 *count*為 NULL,則返回 NULL 。
mysql> **SELECT REPEAT('MySQL', 3);**
??????? -> 'MySQLMySQLMySQL'
- REPLACE(*str*,*from_str*,*to_str*)
返回字符串*str*以及所有被字符串*to_str*替代的字符串*from_str*。
mysql> **SELECT REPLACE('www.mysql.com', 'w', 'Ww');**
??????? -> 'WwWwWw.mysql.com'
這個函數支持多字節字元。
- REVERSE(*str*)
返回字符串 *str*,順序和字符順序相反。
mysql> **SELECT REVERSE('abc');**
????? ??-> 'cba'
這個函數支持多字節字元。
- RIGHT(*str*,*len*)
從字符串*str*開始,返回最右*len* 字符。
mysql> **SELECT RIGHT('foobarbar', 4);**
??????? -> 'rbar'
這個函數支持多字節字元。
- RPAD(*str*,*len*,*padstr*)
返回字符串*str*, 其右邊被字符串 *padstr*填補至*len*字符長度。假如字符串*str*的長度大于 *len*,則返回值被縮短到與 *len*字符相同長度。
mysql> **SELECT RPAD('hi',5,'?');**
??????? -> 'hi???'
mysql> **SELECT RPAD('hi',1,'?');**
??????? -> 'h'
這個函數支持多字節字元。
- RTRIM(*str*)
返回字符串 *str*,結尾空格字符被刪去。
mysql> **SELECT RTRIM('barbar?? ');**
??????? -> 'barbar'
這個函數支持多字節字元。
- SOUNDEX(*str*)
從*str*返回一個soundex字符串。 兩個具有幾乎同樣探測的字符串應該具有同樣的 soundex 字符串。一個標準的soundex 字符串的長度為4個字符,然而SOUNDEX() 函數會返回一個人以長度的字符串。 可使用結果中的SUBSTRING() 來得到一個標準 soundex 字符串。在*str*中*,*會忽略所有未按照字母順序排列的字符。 所有不在A-Z范圍之內的國際字母符號被視為元音字母。
mysql> **SELECT SOUNDEX('Hello');**
??????? -> 'H400'
mysql> **SELECT SOUNDEX('Quadratically');**
?????? ?-> 'Q36324'
**注意:**這個函數執行原始的Soundex算法,而非更加流行的加強版本(如D. Knuth所述)。其區別在于原始版本首先會刪去元音,其次是重復,而加強版則首先刪去重復,而后刪去元音。
- *expr1* SOUNDS LIKE *expr2*
這相當于SOUNDEX(*expr1*) = SOUNDEX(*expr2*)。
- SPACE(*N*)
返回一個由*N*間隔符號組成的字符串。
mysql> **SELECT SPACE(6);**
??????? -> '????? '
- SUBSTRING(*str*,*pos*) , SUBSTRING(*str* FROM *pos*) SUBSTRING(*str*,*pos*,*len*) , SUBSTRING(*str* FROM *pos* FOR *len*)
不帶有*len*參數的格式從字符串*str*返回一個子字符串,起始于位置 *pos*。帶有*len*參數的格式從字符串*str*返回一個長度同*len*字符相同的子字符串,起始于位置 *pos*。 使用 FROM的格式為標準 SQL 語法。也可能對*pos*使用一個負值。假若這樣,則子字符串的位置起始于字符串結尾的*pos*字符,而不是字符串的開頭位置。在以下格式的函數中可以對*pos*使用一個負值。
mysql> **SELECT SUBSTRING('Quadratically',5);**
??????? -> 'ratically'
mysql> **SELECT SUBSTRING('foobarbar' FROM 4);**
??????? -> 'barbar'
mysql> **SELECT SUBSTRING('Quadratically',5,6);**
??????? -> 'ratica'???????
mysql> **SELECT SUBSTRING('Sakila', -3);**
??????? -> 'ila'???????
mysql> **SELECT SUBSTRING('Sakila', -5, 3);**
??????? -> 'aki'
mysql> **SELECT SUBSTRING('Sakila' FROM -4 FOR 2);**
??????? -> 'ki'
這個函數支持多字節字元。
注意,如果對*len*使用的是一個小于1的值,則結果始終為空字符串。
SUBSTR()是 SUBSTRING()的同義詞。
- SUBSTRING_INDEX(*str*,*delim*,*count*)
在定界符 *delim*以及*count*出現前,從字符串*str*返回自字符串。若*count*為正值,則返回最終定界符(從左邊開始)左邊的一切內容。若*count*為負值,則返回定界符(從右邊開始)右邊的一切內容。
mysql> **SELECT SUBSTRING_INDEX('www.mysql.com', '.', 2);**
??????? -> 'www.mysql'
mysql> **SELECT SUBSTRING_INDEX('www.mysql.com', '.', -2);**
??????? -> 'mysql.com'
這個函數支持多字節字元。
- TRIM([{BOTH | LEADING | TRAILING} [*remstr*] FROM] *str*) TRIM(*remstr* FROM] *str*)
返回字符串 *str*, 其中所有*remstr*前綴和/或后綴都已被刪除。若分類符BOTH、LEADIN或TRAILING中沒有一個是給定的,則假設為BOTH 。 *remstr* 為可選項,在未指定情況下,可刪除空格。
mysql> **SELECT TRIM('? bar?? ');**
??????? -> 'bar'
mysql> **SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');**
??????? -> 'barxxx'
mysql> **SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');**
??????? -> 'bar'
mysql> **SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');**
? ??????-> 'barx'
這個函數支持多字節字元。
- UCASE(*str*)
UCASE()是UPPER()的同義詞。
- UNCOMPRESS(*string_to_uncompress*)
對經COMPRESS()函數壓縮后的字符串進行解壓縮。若參數為壓縮值,則結果為 NULL。這個函數要求? MySQL 已被諸如zlib 之類的壓縮庫編譯過。否則, 返回值將始終是 NULL。
mysql> **SELECT UNCOMPRESS(COMPRESS('any string'));**
??????? -> 'any string'
mysql> **SELECT UNCOMPRESS('any string');**
??????? -> NULL
- UNCOMPRESSED_LENGTH(*compressed_string*)
返回壓縮字符串壓縮前的長度。
mysql> **SELECT UNCOMPRESSED_LENGTH(COMPRESS(REPEAT('a',30)));**
??????? -> 30
- UNHEX(*str*)
執行從HEX(*str*)的反向操作。就是說,它將參數中的每一對十六進制數字理解為一個數字,并將其轉化為該數字代表的字符。結果字符以二進制字符串的形式返回。
mysql> **SELECT UNHEX('4D7953514C');**
??????? -> 'MySQL'
mysql> **SELECT 0x4D7953514C;**
??????? -> 'MySQL'
mysql> **SELECT UNHEX(HEX('string'));**
??????? -> 'string'
mysql> **SELECT HEX(UNHEX('1267'));**
??????? -> '1267'
- UPPER(*str*)
返回字符串*str,* 以及根據最新字符集映射轉化為大寫字母的字符 (默認為cp1252 Latin1).
mysql> **SELECT UPPER('Hej');**
??????? -> 'HEJ'
該函數支持多字節字元。
### 12.3.1.?字符串比較函數
根據,MySQL 會自動將數字轉化為字符串,反之亦然。?
mysql> **SELECT 1+'1';**
??????? -> 2
mysql> **SELECT CONCAT(2,' test');**
??????? -> '2 test'
若想要將數字明確地轉化為字符串,可使用 CAST()或 CONCAT()函數:
mysql> **SELECT 38.8, CAST(38.8 AS CHAR);**
??????? -> 38.8, '38.8'
mysql> **SELECT 38.8, CONCAT(38.8);**
??????? -> 38.8, '38.8'
CAST() 比較可取。.
若已經對一個字符串函數給定一個二進制字符串作為參數, 則所得到的結果字符串也是一個二進制字符串。一個轉化為字符串的數字被作為二進制字符串對待。這僅會對比較結果產生影響。
一般而言, 若字符串比較中任意一個表達式是區分大小寫的,則執行比較時也區分大小寫。?
- *expr* LIKE *pat* [ESCAPE '*escape-char*']
模式匹配,使用SQL簡單正規表達式比較。返回1 (TRUE) 或 0 (FALSE)。 若 *expr*或 *pat*中任何一個為 NULL,則結果為 NULL。
模式不需要為文字字符串。例如,可以被指定為一個字符串表達式或表列。
在模式中可以同LIKE一起使用以下兩種通配符:
<table border="1" cellpadding="0" id="table2"><tr><td> <p> <b> <span> 字符</span></b></p></td> <td> <p> <b> <span> 說明</span></b></p></td> </tr><tr><td> <p> <span> %</span></p></td> <td> <p> <span> 匹配任何數目的字符,甚至包括零字符<span>? </span></span></p></td> </tr><tr><td> <p> <span> _</span></p></td> <td> <p> <span> 只能匹配一種字符 </span></p></td> </tr></table>
mysql> **SELECT 'David!' LIKE 'David_';**
??????? -> 1
mysql> **SELECT 'David!' LIKE '%D%v%';**
??????? -> 1
若要對通配符的文字實例進行檢驗, 可將轉義字符放在該字符前面。如果沒有指定 ESCAPE字符, 則假設為‘\’。
<table border="1" cellpadding="0" id="table3"><tr><td> <p> <b> <span> 字符串</span></b></p></td> <td width="103"> <p> <b> <span> 說明</span></b></p></td> </tr><tr><td> <p> <span> \%</span></p></td> <td colspan="2"> <p> <span> 匹配一個<span>? </span>‘<span>%</span>’字符</span></p></td> </tr><tr><td> <p> <span> \_</span></p></td> <td colspan="2"> <p> <span> 匹配一個 ‘<span>_</span>’ 字符</span></p></td> </tr></table>
mysql> **SELECT 'David!' LIKE 'David\_';**
??????? -> 0
mysql> **SELECT 'David_' LIKE 'David\_';**
??????? -> 1
要指定一個不同的轉義字符,可使用ESCAPE語句:
mysql> **SELECT 'David_' LIKE 'David|_' ESCAPE '|';**
??????? -> 1
轉義序列可以為空,也可以是一個字符的長度。 從 MySQL 5.1.2開始, 如若 NO_BACKSLASH_ESCAPES SQL模式被激活, 則該序列不能為空。
以下兩個語句舉例說明了字符串比較不區分大小寫,除非其中一個操作數為二進制字符串:
mysql> **SELECT 'abc' LIKE 'ABC';**
??????? -> 1
mysql> **SELECT 'abc' LIKE BINARY 'ABC';**
??????? -> 0
在MySQL中, LIKE 允許出現在數字表達式中。 (這是標準SQL LIKE 的延伸)。
mysql> **SELECT 10 LIKE '1%';**
??????? -> 1
**注釋**: 由于 MySQL在字符串中使用 C轉義語法(例如, 用‘\n’代表一個換行字符),在LIKE字符串中,必須將用到的‘\’雙寫。例如, 若要查找 ‘\n’, 必須將其寫成 ‘\\n’。而若要查找 ‘\’, 則必須將其寫成 it as ‘\\\\’;原因是反斜線符號會被語法分析程序剝離一次,在進行模式匹配時,又會被剝離一次,最后會剩下一個反斜線符號接受匹配。
- *expr* NOT LIKE *pat* [ESCAPE '*escape-char*']
這相當于 NOT (*expr* LIKE *pat* [ESCAPE '*escape-char*'])。
- *expr* NOT REGEXP *pat**expr* NOT RLIKE *pat*
這相當于NOT (*expr* REGEXP *pat*)。
- *expr* REGEXP *pat**expr* RLIKE *pat*
執行字符串表達式 *expr* 和模式*pat* 的模式匹配。該模式可以被延伸為正規表達式。正規表達式的語法在[附錄G:](#)[*MySQL正則表達式*](# "Appendix?G.?MySQL Regular Expressions")中有詳細討論。若*expr*匹配 *pat,*則返回 1; 否則返回0。若 *expr*或 *pat* 任意一個為 NULL, 則結果為 NULL。 RLIKE 是REGEXP的同義詞, 作用是為mSQL 提供兼容性。
模式不需要為文字字符串。例如,可以被指定為一個字符串表達式或表列。
**注釋**:由于在字符串中, MySQL使用 C 轉義語法 (例如, 用‘\n’來代表換行字符 ),在REGEXP字符串中必須將用到的‘\’ 雙寫。
REGEXP 不區分大小寫, 除非將其同二進制字符串同時使用。
mysql> **SELECT 'Monty!' REGEXP 'm%y%%';**
??????? -> 0
mysql> **SELECT 'Monty!' REGEXP '.*';**
??????? -> 1
mysql> **SELECT 'new*\n*line' REGEXP 'new\\*.\\*line';**
??????? -> 1
mysql> **SELECT 'a' REGEXP 'A', 'a' REGEXP BINARY 'A';**
??????? -> 1? 0
mysql> **SELECT 'a' REGEXP '^[a-d]';**
??????? -> 1
在確定字符類型時,REGEXP 和 RLIKE 使用當前字符集 (默認為cp1252 Latin1 )。 **警告:**這些操作符不支持多字節字元。
- STRCMP(*expr1*,*expr2*)
若所有的字符串均相同,則返回STRCMP(),若根據當前分類次序,第一個參數小于第二個,則返回? -1,其它情況返回 1 。
mysql> **SELECT STRCMP('text', 'text2');**
??????? -> -1
mysql> **SELECT STRCMP('text2', 'text');**
??????? -> 1
mysql> **SELECT STRCMP('text', 'text');**
??????? -> 0
在執行比較時,STRCMP() 使用當前字符集。這使得默認的比較區分大小寫,當操作數中的一個或兩個都是二進制字符串時除外。
### 12.4.?數值函數
[ 12.4.1. 算術操作符](#)[ 12.4.2. 數學函數](#)
### 12.4.1.?算術操作符
可使用常見的算術操作符。注意就 -、 +和 *而言, 若兩個參數均為正數,則其計算結果的精確度為 BIGINT (64比特),若其中一個參數為無符號整數, 而其它參數也是整數, 則結果為無符號整數。請參見[12.8節,“Cast函數和操作符”](# "12.8.?Cast Functions and Operators")。
- +
加號:
mysql> **SELECT 3+5;**
??????? -> 8
- -
減號:
mysql> **SELECT 3-5;**
??????? -> -2
- -
一元減號。更換參數符號。
mysql> **SELECT - 2;**
??????? -> -2
**注意**:若該 操作符同一個BIGINT同時使用,則返回值也是一個BIGINT。這意味著你應當盡量避免對可能產生–263的整數使用 –。
- *
乘號:
mysql> **SELECT 3*5;**
??????? -> 15
mysql> **SELECT 18014398509481984*18014398509481984.0;**
??????? -> 324518553658426726783156020576256.0
mysql> **SELECT 18014398509481984*18014398509481984;**
??????? -> 0
最后一個表達式的結果是不正確的。原因是整數相乘的結果超過了BIGINT 計算的 64比特范圍。 (見[11.2節,“數值類型”](# "11.2.?Numeric Types").)
- /
除號:
mysql> **SELECT 3/5;**
??????? -> 0.60
被零除的結果為 NULL:
mysql> **SELECT 102/(1-1);**
??????? -> NULL
只有當執行的語境中,其結果要被轉化為一個整數時 ,除法才會和 BIGINT 算法一起使用。
- DIV
整數除法。 類似于 FLOOR(),然而使用BIGINT 算法也是可靠的。
mysql> **SELECT 5 DIV 2;**
??????? -> 2
### 12.4.2.?數學函數
若發生錯誤,所有數學函數會返回 NULL 。
- ABS(*X*)
返回*X*的絕對值。
mysql> **SELECT ABS(2);**
??????? -> 2
mysql> **SELECT ABS(-32);**
??????? -> 32
該函數支持使用BIGINT值。
- ACOS(*X*)
返回*X*反余弦, 即, 余弦是*X*的值。若*X*不在-1到 1的范圍之內,則返回 NULL 。
mysql> **SELECT ACOS(1);**
??????? -> 0
mysql> **SELECT ACOS(1.0001);**
??????? -> NULL
mysql> **SELECT ACOS(0);**
??????? -> 1.5707963267949
- ASIN(*X*)
返回*X*的反正弦,即,正弦為*X*的值。若*X*? 若*X*不在-1到 1的范圍之內,則返回 NULL 。
?
~~~
mysql> SELECT ASIN(0.2);
~~~
~~~
??????? -> 0.20135792079033
~~~
~~~
mysql> SELECT ASIN('foo');
~~~
~~~
?
~~~
~~~
+-------------+
~~~
~~~
| ASIN('foo') |
~~~
~~~
+-------------+
~~~
~~~
|?????????? 0 |
~~~
~~~
+-------------+
~~~
~~~
1 row in set, 1 warning (0.00 sec)
~~~
~~~
?
~~~
~~~
mysql> SHOW WARNINGS;
~~~
~~~
+---------+------+-----------------------------------------+
~~~
~~~
| Level?? | Code | Message??????? ?????????????????????????|
~~~
~~~
+---------+------+-----------------------------------------+
~~~
~~~
| Warning | 1292 | Truncated incorrect DOUBLE value: 'foo' |
~~~
~~~
+---------+------+-----------------------------------------+
~~~
- ATAN(*X*)
返回*X*的反正切,即,正切為*X*的值。
mysql> **SELECT ATAN(2);**
??????? -> 1.1071487177941
mysql> **SELECT ATAN(-2);**
??????? -> -1.1071487177941
- ATAN(*Y*,*X*) , ATAN2(*Y*,*X*)
返回兩個變量*X*及*Y*的反正切。 它類似于 *Y*或 *X*的反正切計算,? 除非兩個參數的符號均用于確定結果所在象限。
mysql> **SELECT ATAN(-2,2);**
??????? -> -0.78539816339745
mysql> **SELECT ATAN2(PI(),0);**
??? ????-> 1.5707963267949
- CEILING(*X*) CEIL(*X*)
返回不小于*X*的最小整數值。
mysql> **SELECT CEILING(1.23);**
??????? -> 2
mysql> **SELECT CEIL(-1.23);**
??????? -> -1
這兩個函數的意義相同。注意返回值會被轉化為一個BIGINT。
- COS(*X*)
返回*X*的余弦,其中*X*在弧度上已知。?
mysql> **SELECT COS(PI());**
??????? -> -1
- COT(*X*)
返回*X*的余切。
mysql> **SELECT COT(12);**
??????? -> -1.5726734063977
mysql> **SELECT COT(0);**
??????? -> NULL
- CRC32(*expr*)
計算循環冗余碼校驗值并返回一個 32比特無符號值。若參數為NULL ,則結果為 NULL。該參數應為一個字符串,而且在不是字符串的情況下會被作為字符串處理(若有可能)。
mysql> **SELECT CRC32('MySQL');**
??????? -> 3259397556
mysql> **SELECT CRC32('mysql');**
??????? -> 2501908538
- DEGREES(*X*)
返回參數 *X*, 該參數由弧度被轉化為度。
mysql> **SELECT DEGREES(PI());**
??????? -> 180
mysql> **SELECT DEGREES(PI() / 2);**
??????? -> 90
- EXP(*X*)
返回e的*X*乘方后的值(自然對數的底)。
mysql> **SELECT EXP(2);**
??????? -> 7.3890560989307
mysql> **SELECT EXP(-2);**
??????? -> 0.13533528323661
mysql> **SELECT EXP(0);**
??????? -> 1
- FLOOR(*X*)
返回不大于*X*的最大整數值 。
mysql> **SELECT FLOOR(1.23);**
??????? -> 1
mysql> **SELECT FLOOR(-1.23);**
??????? -> -2
注意,返回值會被轉化為一個 BIGINT。
- FORMAT(*X*,*D*)
將數字*X*的格式寫成'#,###,###.##'格式, 即保留小數點后 *D*位,而第D位的保留方式為四舍五入,然后將結果以字符串的形式返回。詳見[12.9.4節,“其他函數”](# "12.9.4.?Miscellaneous Functions")。
- LN(*X*)
返回*X*的自然對數,即,* X*相對于基數e 的對數。
mysql> **SELECT LN(2);**
??????? -> 0.69314718055995
mysql> **SELECT LN(-2);**
??????? -> NULL
這個函數同LOG(*X*)具有相同意義。
- LOG(*X*) LOG(*B*,*X*)
若用一個參數調用,這個函數就會返回*X*的自然對數。
mysql> **SELECT LOG(2);**
??????? -> 0.69314718055995
mysql> **SELECT LOG(-2);**
??????? -> NULL
若用兩個參數進行調用,這個函數會返回*X*對于任意基數*B* 的對數。
mysql> **SELECT LOG(2,65536);**
??????? -> 16
mysql> **SELECT LOG(10,100);**
? ??????-> 2
LOG(*B*,*X*) 就相當于 LOG(*X*) / LOG(*B*)。
- LOG2(*X*)
返回*X*的基數為2的對數。
mysql> **SELECT LOG2(65536);**
??????? -> 16
mysql> **SELECT LOG2(-100);**
??????? -> NULL
對于查出存儲一個數字需要多少個比特,LOG2()非常有效。這個函數相當于表達式 LOG(*X*) / LOG(2)。
- LOG10(*X*)
返回*X*的基數為10的對數。
mysql> **SELECT LOG10(2);**
? ??????-> 0.30102999566398
mysql> **SELECT LOG10(100);**
??????? -> 2
mysql> **SELECT LOG10(-100);**
??????? -> NULL
LOG10(*X*)相當于LOG(10,*X*)。
- MOD(*N*,*M*) , *N* % *M**N* MOD *M*
模操作。返回*N*被 *M*除后的余數。
mysql> **SELECT MOD(234, 10);**
??????? -> 4
mysql> **SELECT 253 % 7;**
??????? -> 1
mysql> **SELECT MOD(29,9);**
??????? -> 2
mysql> **SELECT 29 MOD 9;**
??????? -> 2
這個函數支持使用BIGINT 值。
MOD() 對于帶有小數部分的數值也起作用, 它返回除法運算后的精確余數:
mysql> **SELECT MOD(34.5,3);**
??????? -> 1.5
- PI()
返回 ? (pi)的值。默認的顯示小數位數是7位,然而 MySQL內部會使用完全雙精度值。
mysql> **SELECT PI();**
??????? -> 3.141593
mysql> **SELECT PI()+0.000000000000000000;**
??????? -> 3.141592653589793116
- POW(*X*,*Y*) , POWER(*X*,*Y*)
返回*X*的*Y*乘方的結果值。
mysql> **SELECT POW(2,2);**
??????? -> 4
mysql> **SELECT POW(2,-2);**
??????? -> 0.25
- RADIANS(*X*)
返回由度轉化為弧度的參數 *X*,? (注意 ?弧度等于180度)。
mysql> **SELECT RADIANS(90);**
??????? -> 1.5707963267949
- RAND() RAND(*N*)
返回一個隨機浮點值 *v* ,范圍在 0 到1 之間 (即, 其范圍為 0 ≤ *v*≤ 1.0)。若已指定一個整數參數 *N*,則它被用作種子值,用來產生重復序列。?
mysql> **SELECT RAND();**
??????? -> 0.9233482386203
mysql> **SELECT RAND(20);**
??????? -> 0.15888261251047
mysql> **SELECT RAND(20);**
??????? -> 0.15888261251047
mysql> **SELECT RAND();**
??????? -> 0.63553050033332
mysql> **SELECT RAND();**
??????? -> 0.70100469486881
mysql> **SELECT RAND(20);**
??????? -> 0.15888261251047
若要在*i*≤ *R*≤ *j*這個范圍得到一個隨機整數*R*,需要用到表達式 FLOOR(*i* + RAND() * (*j*– *i* + 1))。例如, 若要在7 到 12 的范圍(包括7和12)內得到一個隨機整數, 可使用以下語句:
SELECT FLOOR(7 + (RAND() * 6));
在ORDER BY語句中,不能使用一個帶有RAND()值的列,原因是 ORDER BY 會計算列的多重時間。然而,可按照如下的隨機順序檢索數據行:
mysql> **SELECT * FROM *tbl_name* ORDER BY RAND();**
ORDER BY RAND()同 LIMIT 的結合從一組列中選擇隨機樣本很有用:
mysql> **SELECT * FROM table1, table2 WHERE a=b AND c<d**
??? -> **ORDER BY RAND() LIMIT 1000;**
注意,在WHERE語句中,WHERE每執行一次, RAND()就會被再計算一次。
RAND()的作用不是作為一個精確的隨機發生器,而是一種用來發生在同樣的 MySQL版本的平臺之間的可移動*ad hoc*隨機數的快速方式。
- ROUND(*X*) ROUND(*X*,*D*)
返回參數*X*, 其值接近于最近似的整數。在有兩個參數的情況下,返回 *X*,其值保留到小數點后*D*位,而第*D*位的保留方式為四舍五入。若要接保留*X*值小數點左邊的*D*位,可將 *D* 設為負值。
mysql> **SELECT ROUND(-1.23);**
??????? -> -1
mysql> **SELECT ROUND(-1.58);**
??????? -> -2
mysql> **SELECT ROUND(1.58);**
??????? -> 2
mysql> **SELECT ROUND(1.298, 1);**
??????? -> 1.3
mysql> **SELECT ROUND(1.298, 0);**
??? ????-> 1
mysql> **SELECT ROUND(23.298, -1);**
??????? -> 20
返回值的類型同 第一個自變量相同(假設它是一個整數、雙精度數或小數)。這意味著對于一個整數參數,結果也是一個整數(無小數部分)。
當第一個參數是十進制常數時,對于準確值參數,ROUND() 使用精密數學題庫:
- 對于準確值數字, ROUND() 使用“四舍五入” 或“舍入成最接近的數” 的規則:對于一個分數部分為 .5或大于 .5的值,正數則上舍入到鄰近的整數值, 負數則下舍入臨近的整數值。(換言之, 其舍入的方向是數軸上遠離零的方向)。對于一個分數部分小于.5 的值,正數則下舍入下一個整數值,負數則下舍入鄰近的整數值,而正數則上舍入鄰近的整數值。
- 對于近似值數字,其結果根據C 庫而定。在很多系統中,這意味著 ROUND()的使用遵循“舍入成最接近的偶數”的規則: 一個帶有任何小數部分的值會被舍入成最接近的偶數整數。
以下舉例說明舍入法對于精確值和近似值的不同之處:
mysql> **SELECT ROUND(2.5), ROUND(25E-1);**
+------------+--------------+
| ROUND(2.5) | ROUND(25E-1) |
+------------+--------------+
| 3????????? |??????????? 2 |
+------------+--------------+
詳見[第24章:](#)[*精度數學*](# "Chapter?24.?Precision Math")。
- SIGN(*X*)
返回參數作為-1、 0或1的符號,該符號取決于*X*的值為負、零或正。
mysql> **SELECT SIGN(-32);**
??????? -> -1
mysql> **SELECT SIGN(0);**
??????? -> 0
mysql> **SELECT SIGN(234);**
??????? -> 1
- SIN(*X*)
返回*X*正弦,其中 *X* 在弧度中被給定。
mysql> **SELECT SIN(PI());**
??????? -> 1.2246063538224e-16
mysql> **SELECT ROUND(SIN(PI()));**
??????? -> 0
- SQRT(*X*)
返回非負數*X*的二次方根。
mysql> **SELECT SQRT(4);**
??????? -> 2
mysql> **SELECT SQRT(20);**
??????? -> 4.4721359549996
mysql> **SELECT SQRT(-16);**
??????? -> NULL???????
- TAN(*X*)
返回*X*的正切,其中*X* 在弧度中被給定。
mysql> **SELECT TAN(PI());**
??????? -> -1.2246063538224e-16
mysql> **SELECT TAN(PI()+1);**
??????? -> 1.5574077246549
- TRUNCATE(*X*,*D*)
返回被舍去至小數點后*D*位的數字*X*。若*D*的值為 0, 則結果不帶有小數點或不帶有小數部分。可以將D設為負數,若要截去(歸零) X小數點左起第D位開始后面所有低位的值.*?*
mysql> **SELECT TRUNCATE(1.223,1);**
??????? -> 1.2
mysql> **SELECT TRUNCATE(1.999,1);**
??????? -> 1.9
mysql> **SELECT TRUNCATE(1.999,0);**
??????? -> 1
mysql> **SELECT TRUNCATE(-1.999,1);**
??????? -> -1.9
mysql> **SELECT TRUNCATE(122,-2);**
?????? -> 100
mysql> **SELECT TRUNCATE(10.28*100,0);**
?????? -> 1028
所有數字的舍入方向都接近于零。
### 12.5.?日期和時間函數
本章論述了一些可用于操作時間值的函數。關于每個時間和日期類型具有的值域及指定值的有效格式,請參見[11.3節,“日期和時間類型”](# "11.3.?Date and Time Types")。
下面的例子使用了時間函數。以下詢問選擇了最近的 30天內所有帶有date_col 值的記錄:
mysql> **SELECT *something* FROM *tbl_name***
??? -> **WHERE DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= *date_col*;**
注意,這個詢問也能選擇將來的日期記錄。?
用于日期值的函數通常會接受時間日期值而忽略時間部分。而用于時間值的函數通常接受時間日期值而忽略日期部分。
返回各自當前日期或時間的函數在每次詢問執行開始時計算一次。這意味著在一個單一詢問中,對諸如NOW() 的函數多次訪問總是會得到同樣的結果(未達到我們的目的,單一詢問也包括對存儲程序或觸發器和被該程序/觸發器調用的所有子程序的調用 )。這項原則也適用于 CURDATE()、 CURTIME()、 UTC_DATE()、 UTC_TIME()、UTC_TIMESTAMP(),以及所有和它們意義相同的函數。
CURRENT_TIMESTAMP()、 CURRENT_TIME()、 CURRENT_DATE()以及FROM_UNIXTIME()函數返回連接當前時區內的值,這個值可用作time_zone系統變量的值。此外, UNIX_TIMESTAMP() 假設其參數為一個當前時區的時間日期值。請參見[5.10.8節,“MySQL服務器時區支持”](# "5.10.8.?MySQL Server Time Zone Support")。
以下函數的論述中返回值的范圍會請求完全日期。 若一個日期為“零” 值,或者是一個諸如'2001-11-00'之類的不完全日期, 提取部分日期值的函數可能會返回 0。 例如, DAYOFMONTH('2001-11-00') 會返回0。
- ADDDATE(*date*,INTERVAL *expr**type*) ADDDATE(*expr*,*days*)
當被第二個參數的INTERVAL格式激活后, ADDDATE()就是DATE_ADD()的同義詞。相關函數SUBDATE() 則是DATE_SUB()的同義詞。對于INTERVAL參數上的信息 ,請參見關于DATE_ADD()的論述。
mysql> **SELECT DATE_ADD('1998-01-02', INTERVAL 31 DAY);**
??????? -> '1998-02-02'
mysql> **SELECT ADDDATE('1998-01-02', INTERVAL 31 DAY);**
??????? -> '1998-02-02'
若 *days*參數只是整數值,則 MySQL 5.1將其作為天數值添加至 *expr*。
mysql> **SELECT ADDDATE('1998-01-02', 31);**
??????? -> '1998-02-02'
- ADDTIME(*expr*,*expr2*)
ADDTIME()將 *expr2*添加至*expr*然后返回結果。 *expr* 是一個時間或時間日期表達式,而*expr2*是一個時間表達式。
mysql> **SELECT ADDTIME('1997-12-31 23:59:59.999999',**
??? ->?? ?????????????**'1 1:1:1.000002');**
??????? -> '1998-01-02 01:01:01.000001'
mysql> **SELECT ADDTIME('01:00:00.999999', '02:00:00.999998');**
??????? -> '03:00:01.999997'
- CONVERT_TZ(*dt*,*from_tz*,*to_tz*)
CONVERT_TZ() 將時間日期值*dt*從*from_tz* 給出的時區轉到*to_tz*給出的時區,然后返回結果值。關于可能指定的時區的詳細論述,請參見[5.10.8節,“MySQL服務器時區支持”](# "5.10.8.?MySQL Server Time Zone Support")。若自變量無效,則這個函數會返回 NULL。
在從若*from_tz*到UTC的轉化過程中,該值超出 TIMESTAMP 類型的被支持范圍,那么轉化不會發生。關于 TIMESTAMP 范圍的論述,請參見[11.1.2節,“日期和時間類型概述”](# "11.1.2.?Overview of Date and Time Types")。
mysql> **SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');**
??????? -> '2004-01-01 13:00:00'
mysql> **SELECT CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00');**
??????? -> '2004-01-01 22:00:00'
**注釋**:若要使用諸如 'MET'或 'Europe/Moscow'之類的指定時間區,首先要設置正確的時區表。詳細說明見[5.10.8節,“MySQL服務器時區支持”](# "5.10.8.?MySQL Server Time Zone Support")。?
- CURDATE()
將當前日期按照'YYYY-MM-DD' 或YYYYMMDD 格式的值返回,具體格式根據函數用在字符串或是數字語境中而定。
mysql> **SELECT CURDATE();**
??????? -> '1997-12-15'
mysql> **SELECT CURDATE() + 0;**
??????? -> 19971215
- CURRENT_DATE CURRENT_DATE()
CURRENT_DATE和CURRENT_DATE()是的同義詞.
- CURTIME()
將當前時間以'HH:MM:SS'或 HHMMSS 的格式返回, 具體格式根據函數用在字符串或是數字語境中而定。?
mysql> **SELECT CURTIME();**
??????? -> '23:50:26'
mysql> **SELECT CURTIME() + 0;**
??????? -> 235026
- CURRENT_TIME, CURRENT_TIME()
CURRENT_TIME 和CURRENT_TIME() 是CURTIME()的同義詞。
- CURRENT_TIMESTAMP, CURRENT_TIMESTAMP()
CURRENT_TIMESTAMP和 CURRENT_TIMESTAMP()是NOW()的同義詞。
- DATE(*expr*)
提取日期或時間日期表達式*expr*中的日期部分。
mysql> **SELECT DATE('2003-12-31 01:02:03');**
??????? -> '2003-12-31'
- DATEDIFF(*expr*,*expr2*)
DATEDIFF() 返回起始時間 *expr*和結束時間*expr2*之間的天數。*Expr*和*expr2*為日期或 date-and-time 表達式。計算中只用到這些值的日期部分。
mysql> **SELECT DATEDIFF('1997-12-31 23:59:59','1997-12-30');**
??????? -> 1
mysql> **SELECT DATEDIFF('1997-11-30 23:59:59','1997-12-31');**
??????? -> -31
- DATE_ADD(*date*,INTERVAL *expr**type*) DATE_SUB(*date*,INTERVAL *expr**type*)
這些函數執行日期運算。 *date* 是一個 DATETIME 或DATE值,用來指定起始時間。 *expr* 是一個表達式,用來指定從起始日期添加或減去的時間間隔值。? *Expr*是一個字符串;對于負值的時間間隔,它可以以一個 ‘-’開頭。 *type*為關鍵詞,它指示了表達式被解釋的方式。?
關鍵詞INTERVA及 *type*分類符均不區分大小寫。
以下表顯示了*type*和*expr*參數的關系:
<table border="1" cellpadding="0" id="table4"><tr><td> <p><i> <span> type</span></i><span> </span><b> <span>值</span></b></p></td> <td> <p><b> <span> 預期的</span></b><span> <i><span>expr</span></i><span> </span> <b>格式</b></span></p></td> </tr><tr><td> <p> <span> MICROSECOND</span></p></td> <td> <p> <span> MICROSECONDS</span></p></td> </tr><tr><td> <p> <span> SECOND</span></p></td> <td> <p> <span> SECONDS</span></p></td> </tr><tr><td> <p> <span> MINUTE</span></p></td> <td> <p> <span> MINUTES</span></p></td> </tr><tr><td> <p> <span> HOUR</span></p></td> <td> <p> <span> HOURS</span></p></td> </tr><tr><td> <p> <span> DAY</span></p></td> <td> <p> <span> DAYS</span></p></td> </tr><tr><td> <p> <span> WEEK</span></p></td> <td> <p> <span> WEEKS</span></p></td> </tr><tr><td> <p> <span> MONTH</span></p></td> <td> <p> <span> MONTHS</span></p></td> </tr><tr><td> <p> <span> QUARTER</span></p></td> <td> <p> <span> QUARTERS</span></p></td> </tr><tr><td> <p> <span> YEAR</span></p></td> <td> <p> <span> YEARS</span></p></td> </tr><tr><td> <p> <span> SECOND_MICROSECOND</span></p></td> <td> <p> <span> 'SECONDS.MICROSECONDS'</span></p></td> </tr><tr><td> <p> <span> MINUTE_MICROSECOND</span></p></td> <td> <p> <span> 'MINUTES.MICROSECONDS'</span></p></td> </tr><tr><td> <p> <span> MINUTE_SECOND</span></p></td> <td> <p> <span> 'MINUTES:SECONDS'</span></p></td> </tr><tr><td> <p> <span> HOUR_MICROSECOND</span></p></td> <td> <p> <span> 'HOURS.MICROSECONDS'</span></p></td> </tr><tr><td> <p> <span> HOUR_SECOND</span></p></td> <td> <p> <span> 'HOURS:MINUTES:SECONDS'</span></p></td> </tr><tr><td> <p> <span> HOUR_MINUTE</span></p></td> <td> <p> <span> 'HOURS:MINUTES'</span></p></td> </tr><tr><td> <p> <span> DAY_MICROSECOND</span></p></td> <td> <p> <span> 'DAYS.MICROSECONDS'</span></p></td> </tr><tr><td> <p> <span> DAY_SECOND</span></p></td> <td> <p> <span> 'DAYS HOURS:MINUTES:SECONDS'</span></p></td> </tr><tr><td> <p> <span> DAY_MINUTE</span></p></td> <td> <p> <span> 'DAYS HOURS:MINUTES'</span></p></td> </tr><tr><td> <p> <span> DAY_HOUR</span></p></td> <td> <p> <span> 'DAYS HOURS'</span></p></td> </tr><tr><td> <p> <span> YEAR_MONTH</span></p></td> <td> <p> <span> 'YEARS-MONTHS'</span></p></td> </tr></table>
MySQL 允許任何*expr*格式中的標點分隔符。表中所顯示的是建議的 分隔符。若 *date*參數是一個 DATE 值,而你的計算只會包括 YEAR、MONTH和DAY部分(即, 沒有時間部分), 其結果是一個DATE 值。否則,結果將是一個 DATETIME值。
若位于另一端的表達式是一個日期或日期時間值 , 則INTERVAL *expr**type*只允許在 + 操作符的兩端。對于 –操作符,? INTERVAL *expr**type*只允許在其右端,原因是從一個時間間隔中提取一個日期或日期時間值是毫無意義的。 (見下面的例子)。
mysql> **SELECT '1997-12-31 23:59:59' + INTERVAL 1 SECOND;**
??????? -> '1998-01-01 00:00:00'
mysql> **SELECT INTERVAL 1 DAY + '1997-12-31';**
??????? -> '1998-01-01'
mysql> **SELECT '1998-01-01' - INTERVAL 1 SECOND;**
??????? -> '1997-12-31 23:59:59'
mysql> **SELECT DATE_ADD('1997-12-31 23:59:59',**
??? ->???????????????? **INTERVAL 1 SECOND);**
??????? -> '1998-01-01 00:00:00'
mysql> **SELECT DATE_ADD('1997-12-31 23:59:59',**
??? ->???????????????? **INTERVAL 1 DAY);**
??????? -> '1998-01-01 23:59:59'
mysql> **SELECT DATE_ADD('1997-12-31 23:59:59',**
??? ->???????????????? **INTERVAL '1:1' MINUTE_SECOND);**
??????? -> '1998-01-01 00:01:00'
mysql> **SELECT DATE_SUB('1998-01-01 00:00:00',**
??? ->???????????????? **INTERVAL '1 1:1:1' DAY_SECOND);**
??????? -> '1997-12-30 22:58:59'
mysql> **SELECT DATE_ADD('1998-01-01 00:00:00',**
??? ->???????????????? **INTERVAL '-1 10' DAY_HOUR);**
??????? -> '1997-12-30 14:00:00'
mysql> **SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY);**
??????? -> '1997-12-02'
mysql> **SELECT DATE_ADD('1992-12-31 23:59:59.000002',**
??? ->??????????? **INTERVAL '1.999999' SECOND_MICROSECOND);**
??????? -> '1993-01-01 00:00:01.000001'
若你指定了一個過于短的時間間隔值 (不包括*type*關鍵詞所預期的所有時間間隔部分), MySQL 假定你已經省去了時間間隔值的最左部分。 例如,你指定了一種類型的DAY_SECOND,* expr*的值預期應當具有天、 小時、分鐘和秒部分。若你指定了一個類似 '1:10'的值, MySQL 假定天和小時部分不存在,那么這個值代表分和秒。換言之, '1:10' DAY_SECOND 被解釋為相當于 '1:10' MINUTE_SECOND。這相當于 MySQL將TIME 值解釋為所耗費的時間而不是日時的解釋方式。?????????????
假如你對一個日期值添加或減去一些含有時間部分的內容,則結果自動轉化為一個日期時間值:
mysql> **SELECT DATE_ADD('1999-01-01', INTERVAL 1 DAY);**
??????? -> '1999-01-02'
mysql> **SELECT DATE_ADD('1999-01-01', INTERVAL 1 HOUR);**
??????? -> '1999-01-01 01:00:00'
假如你使用了格式嚴重錯誤的日期,則結果為 NULL。假如你添加了? MONTH、YEAR_MONTH或YEAR ,而結果日期中有一天的日期大于添加的月份的日期最大限度,則這個日期自動被調整為添加月份的最大日期:
mysql> **SELECT DATE_ADD('1998-01-30', INTERVAL 1 MONTH);**
??????? -> '1998-02-28'
- DATE_FORMAT(*date*,*format*)
根據*format*字符串安排*date* 值的格式。
以下說明符可用在 *format*字符串中:
<table border="1" cellpadding="0" width="531"><tr><td width="59"> <p><b> <span> 說明符</span></b></p></td> <td> <p><strong> <span>說明</span></strong></p></td> </tr><tr><td width="59"> <p> <span>%a</span></p></td> <td> <p> 工作日的縮寫名稱? (Sun..Sat)</p></td> </tr><tr><td width="59"> <p> <span>%b</span></p></td> <td> <p> <span>月份的縮寫名稱</span><span>? (</span><span>Jan</span><span>..</span><span>Dec</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%c</span></p></td> <td> <p> <span>月份,數字形式</span><span>(</span><span>0</span><span>..</span><span>12</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%D</span></p></td> <td> <p> <span>帶有英語后綴的該月日期</span><span>? (</span><span>0th</span><span>, </span> <span>1st</span><span>, </span> <span>2nd</span><span>, </span> <span>3rd</span><span>, ...)</span></p></td> </tr><tr><td width="59"> <p> <span>%d</span></p></td> <td> <p> <span>該月日期</span><span>, </span><span>數字形式</span><span> (</span><span>00</span><span>..</span><span>31</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%e</span></p></td> <td> <p> <span>該月日期</span><span>, </span><span>數字形式</span><span>(</span><span>0</span><span>..</span><span>31</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%f</span></p></td> <td> <p> <span>微秒</span><span> (</span><span>000000</span><span>..</span><span>999999</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%H</span></p></td> <td> <p> <span>小時</span><span>(</span><span>00</span><span>..</span><span>23</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%h</span></p></td> <td> <p> <span>小時</span><span>(</span><span>01</span><span>..</span><span>12</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%I</span></p></td> <td> <p> <span>小時</span><span> (</span><span>01</span><span>..</span><span>12</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%i</span></p></td> <td> <p> <span>分鐘</span><span>,</span><span>數字形式</span><span> (</span><span>00</span><span>..</span><span>59</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%j</span></p></td> <td> <p> <span>一年中的天數</span><span> (</span><span>001</span><span>..</span><span>366</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%k</span></p></td> <td> <p> <span>小時</span><span> (</span><span>0</span><span>..</span><span>23</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%l</span></p></td> <td> <p> <span>小時</span><span> (</span><span>1</span><span>..</span><span>12</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%M</span></p></td> <td> <p> <span>月份名稱</span><span> (</span><span>January</span><span>..</span><span>December</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%m</span></p></td> <td> <p> <span>月份</span><span>, </span><span>數字形式</span><span> (</span><span>00</span><span>..</span><span>12</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%p</span></p></td> <td> <p> <span>上午(<span>AM</span>)或下午(</span><span> </span><span> <span>PM</span><span>)</span></span></p></td> </tr><tr><td width="59"> <p> <span>%r</span></p></td> <td> <p> <span>時間</span><span> , 12</span><span>小時制</span><span> (</span><span>小時<span>hh:</span>分鐘<span>mm:</span>秒數<span>ss</span></span><span> </span><span>后加</span><span> </span> <span>AM</span><span>或</span><span>PM</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%S</span></p></td> <td> <p> <span>秒</span><span> (</span><span>00</span><span>..</span><span>59</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%s</span></p></td> <td> <p> <span>秒</span><span> (</span><span>00</span><span>..</span><span>59</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%T</span></p></td> <td> <p> <span>時間</span><span> , 24</span><span>小時制</span><span> (</span><span>小時<span>hh:</span>分鐘<span>mm:</span>秒數<span>ss</span></span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%U</span></p></td> <td> <p> <span>周</span><span> (</span><span>00</span><span>..</span><span>53</span><span>), </span><span> 其中周日為每周的第一天</span><span> </span></p></td> </tr><tr><td width="59"> <p> <span>%u</span></p></td> <td> <p> <span>周</span><span> (</span><span>00</span><span>..</span><span>53</span><span>), </span><span> 其中周一為每周的第一天</span><span>? </span></p></td> </tr><tr><td width="59"> <p> <span>%V</span></p></td> <td> <p> <span>周</span><span> (</span><span>01</span><span>..</span><span>53</span><span>), </span><span> 其中周日為每周的第一天</span><span> ; </span><span>和</span><span> </span><span> <span>%X</span><span>同時使用</span></span></p></td> </tr><tr><td width="59"> <p> <span>%v</span></p></td> <td> <p> <span>周</span><span> (</span><span>01</span><span>..</span><span>53</span><span>), </span><span> 其中周一為每周的第一天</span><span> ; </span><span>和</span><span> </span><span> <span>%x</span><span>同時使用</span></span></p></td> </tr><tr><td width="59"> <p> <span>%W</span></p></td> <td> <p> <span>工作日名稱</span><span> (</span><span>周日</span><span>..</span><span>周六</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%w</span></p></td> <td> <p> <span>一周中的每日</span><span> (</span><span>0</span><span>=</span><span>周日</span><span>..</span><span>6</span><span>=</span><span>周六</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%X</span></p></td> <td> <p> <span> 該周的年份,其中周日為每周的第一天</span><span>, </span><span>數字形式</span><span>,4</span><span>位數</span><span>;</span><span>和</span><span><span>%V</span><span>同時使用</span></span></p></td> </tr><tr><td width="59"> <p> <span>%x</span></p></td> <td> <p> <span> 該周的年份,其中周一為每周的第一天</span><span>, </span><span>數字形式</span><span>,4</span><span>位數</span><span>;</span><span>和</span><span><span>%v</span><span>同時使用</span></span><span> </span></p></td> </tr><tr><td width="59"> <p> <span>%Y</span></p></td> <td> <p> <span>年份</span><span>, </span><span>數字形式</span><span>,4</span><span>位數</span></p></td> </tr><tr><td width="59"> <p> <span>%y</span></p></td> <td> <p> <span>年份</span><span>, </span><span>數字形式</span><span> (2</span><span>位數</span><span>)</span></p></td> </tr><tr><td width="59"> <p> <span>%%</span></p></td> <td> <p> <span>‘</span><span>%</span><span>’文字字符</span></p></td> </tr></table>
所有其它字符都被復制到結果中,無需作出解釋。
注意, ‘%’字符要求在格式指定符之前。
月份和日期說明符的范圍從零開始,原因是 MySQL允許存儲諸如 '2004-00-00'的不完全日期.
~~~
mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y');
~~~
~~~
??????? -> 'Saturday October 1997'
~~~
~~~
mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');
~~~
~~~
??????? -> '22:23:00'
~~~
~~~
mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
~~~
~~~
????????????????????????? '%D %y %a %d %m %b %j');
~~~
~~~
??????? -> '4th 97 Sat 04 10 Oct 277'
~~~
~~~
mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
~~~
~~~
????????????????????????? '%H %k %I %r %T %S %w');
~~~
~~~
??????? -> '22 22 10 10:23:00 PM 22:23:00 00 6'
~~~
~~~
mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
~~~
~~~
??????? -> '1998 52'
~~~
- DAY(*date*)
DAY() 和DAYOFMONTH()的意義相同。
- DAYNAME(*date*)
返回*date*對應的工作日名稱。
mysql> **SELECT DAYNAME('1998-02-05');**
??????? -> '周四'
- DAYOFMONTH(*date*)
返回*date*對應的該月日期,范圍是從 1到31。
mysql> **SELECT DAYOFMONTH('1998-02-03');**
??????? -> 3
- DAYOFWEEK(*date*)
返回*date* (1 = 周日, 2 = 周一, ..., 7 = 周六)對應的工作日索引。這些索引值符合 ODBC標準。
mysql> **SELECT DAYOFWEEK('1998-02-03');**
??????? -> 3
- DAYOFYEAR(*date*)
返回*date*對應的一年中的天數,范圍是從 1到366。
mysql> **SELECT DAYOFYEAR('1998-02-03');**
??????? -> 34
- EXTRACT(*type* FROM *date*)
EXTRACT()函數所使用的時間間隔類型說明符同 DATE_ADD()或DATE_SUB()的相同,但它從日期中提取其部分,而不是執行日期運算。?
mysql> **SELECT EXTRACT(YEAR FROM '1999-07-02');**
?????? -> 1999
mysql> **SELECT EXTRACT(YEAR_MONTH FROM '1999-07-02 01:02:03');**
?????? -> 199907
mysql> **SELECT EXTRACT(DAY_MINUTE FROM '1999-07-02 01:02:03');**
?????? -> 20102
mysql> **SELECT EXTRACT(MICROSECOND**
??? ->??????????????? **FROM '2003-01-02 10:30:00.00123');**
??????? -> 123
- FROM_DAYS(*N*)
給定一個天數? *N*, 返回一個DATE值。
mysql> **SELECT FROM_DAYS(729669);**
??????? -> '1997-10-07'
使用 FROM_DAYS()處理古老日期時,務必謹慎。他不用于處理陽歷出現前的日期(1582)。請參見[12.6節,“MySQL使用什么日歷?”](# "12.6.?What Calendar Is Used By MySQL?")。
- FROM_UNIXTIME(*unix_timestamp*) , FROM_UNIXTIME(*unix_timestamp*,*format*)
返回'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS 格式值的*unix_timestamp*參數表示,具體格式取決于該函數是否用在字符串中或是數字語境中。
若*format*已經給出,則結果的格式是根據*format*字符串而定。 *format*可以包含同DATE_FORMAT() 函數輸入項列表中相同的說明符。
mysql> **SELECT FROM_UNIXTIME(875996580);**
??????? -> '1997-10-04 22:23:00'
mysql> **SELECT FROM_UNIXTIME(875996580) + 0;**
??????? -> 19971004222300
mysql> **SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(),**
??? ->????????????????????? **'%Y %D %M %h:%i:%s %x');**
??????? -> '2003 6th August 06:22:58 2003'
- GET_FORMAT(DATE|TIME|DATETIME, 'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL')
返回一個格式字符串。這個函數在同DATE_FORMAT() 及STR_TO_DATE()函數結合時很有用。
第一個參數的3個可能值和第二個參數的5個可能值產生 15 個可能格式字符串 (對于使用的說明符,請參見DATE_FORMAT()函數說明表 )。
<table border="1" cellpadding="0" id="table6"><tr><td> <p><b> <span> 函數調用</span></b></p></td> <td> <p><b> <span> 結果</span></b></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATE,'USA')</span></p></td> <td> <p> <span> '%m.%d.%Y'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATE,'JIS')</span></p></td> <td> <p> <span> '%Y-%m-%d'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATE,'ISO')</span></p></td> <td> <p> <span> '%Y-%m-%d'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATE,'EUR')</span></p></td> <td> <p> <span> '%d.%m.%Y'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATE,'INTERNAL')</span></p></td> <td> <p> <span> '%Y%m%d'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATETIME,'USA')</span></p></td> <td> <p> <span> '%Y-%m-%d-%H.%i.%s'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATETIME,'JIS')</span></p></td> <td> <p> <span> '%Y-%m-%d %H:%i:%s'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATETIME,'ISO')</span></p></td> <td> <p> <span> '%Y-%m-%d %H:%i:%s'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATETIME,'EUR')</span></p></td> <td> <p> <span> '%Y-%m-%d-%H.%i.%s'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(DATETIME,'INTERNAL')</span></p></td> <td> <p> <span> '%Y%m%d%H%i%s'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(TIME,'USA')</span></p></td> <td> <p> <span> '%h:%i:%s %p'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(TIME,'JIS')</span></p></td> <td> <p> <span> '%H:%i:%s'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(TIME,'ISO')</span></p></td> <td> <p> <span> '%H:%i:%s'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(TIME,'EUR')</span></p></td> <td> <p> <span> '%H.%i.%S'</span></p></td> </tr><tr><td> <p> <span> GET_FORMAT(TIME,'INTERNAL')</span></p></td> <td> <p> <span> '%H%i%s'</span></p></td> </tr></table>
ISO 格式為ISO 9075, 而非ISO 8601.
也可以使用TIMESTAMP, 這時GET_FORMAT()的返回值和DATETIME相同。
mysql> **SELECT DATE_FORMAT('2003-10-03',GET_FORMAT(DATE,'EUR'));**
??????? -> '03.10.2003'
mysql> **SELECT STR_TO_DATE('10.31.2003',GET_FORMAT(DATE,'USA'));**
??????? -> '2003-10-31'
或見[13.5.3節,“SET語法”](# "13.5.3.?SET Syntax")。
- HOUR(*time*)
返回*time*對應的小時數。對于日時值的返回值范圍是從 0 到 23 。
mysql> **SELECT HOUR('10:05:03');**
??????? -> 10
然而,? TIME 值的范圍實際上非常大, 所以HOUR可以返回大于23的值。
mysql> **SELECT HOUR('272:59:59');**
??????? -> 272
- LAST_DAY(*date*)
獲取一個日期或日期時間值,返回該月最后一天對應的值。若參數無效,則返回NULL。
mysql> **SELECT LAST_DAY('2003-02-05');**
??????? -> '2003-02-28'
mysql> **SELECT LAST_DAY('2004-02-05');**
??????? -> '2004-02-29'
mysql> **SELECT LAST_DAY('2004-01-01 01:01:01');**
??????? -> '2004-01-31'
mysql> **SELECT LAST_DAY('2003-03-32');**
??????? -> NULL
- LOCALTIME, LOCALTIME()
LOCALTIME 及 LOCALTIME()和NOW()具有相同意義。
- LOCALTIMESTAMP, LOCALTIMESTAMP()
LOCALTIMESTAMP和LOCALTIMESTAMP()和NOW()具有相同意義。
- MAKEDATE(*year*,*dayofyear*)
給出年份值和一年中的天數值,返回一個日期。*dayofyear*必須大于 0 ,否則結果為 NULL。
mysql> **SELECT MAKEDATE(2001,31), MAKEDATE(2001,32);**
??????? -> '2001-01-31', '2001-02-01'
mysql> **SELECT MAKEDATE(2001,365), MAKEDATE(2004,365);**
??????? -> '2001-12-31', '2004-12-30'
mysql> **SELECT MAKEDATE(2001,0);**
??????? -> NULL
- MAKETIME(*hour*,*minute*,*second*)
返回由*hour*、 *minute*和*second*參數計算得出的時間值。
mysql> **SELECT MAKETIME(12,15,30);**
??????? -> '12:15:30'
- MICROSECOND(*expr*)
從時間或日期時間表達式*expr*返回微秒值,其數字范圍從 0到 999999。
mysql> **SELECT MICROSECOND('12:00:00.123456');**
??????? -> 123456
mysql> **SELECT MICROSECOND('1997-12-31 23:59:59.000010');**
??????? -> 10
- MINUTE(*time*)
返回* time*對應的分鐘數,范圍是從 0 到 59。
mysql> **SELECT MINUTE('98-02-03 10:05:03');**
??????? -> 5
- MONTH(*date*)
返回*date*對應的月份,范圍時從 1 到 12。
mysql> **SELECT MONTH('1998-02-03');**
??????? -> 2
- MONTHNAME(*date*)
返回*date*對應月份的全名。
mysql> **SELECT MONTHNAME('1998-02-05');**
??????? -> 'February '
- NOW()
返回當前日期和時間值,其格式為 'YYYY-MM-DD HH:MM:SS' 或YYYYMMDDHHMMSS , 具體格式取決于該函數是否用在字符串中或數字語境中。
mysql> **SELECT NOW();**
??????? -> '1997-12-15 23:50:26'
mysql> **SELECT NOW() + 0;**
??????? -> 19971215235026
在一個存儲程序或觸發器內, NOW() 返回一個常數時間,該常數指示了該程序或觸發語句開始執行的時間。這同SYSDATE()的運行有所不同。
- PERIOD_ADD(*P*,*N*)
添加 *N*個月至周期*P* (格式為YYMM 或YYYYMM),返回值的格式為 YYYYMM。注意周期參數 *P**不是*日期值。?
mysql> **SELECT PERIOD_ADD(9801,2);**
??????? -> 199803
- PERIOD_DIFF(*P1*,*P2*)?
返回周期*P1*和 *P2*之間的月份數。*P1*和*P2*的格式應該為YYMM或YYYYMM。注意周期參數 *P1*和*P2**不是*日期值。
mysql> **SELECT PERIOD_DIFF(9802,199703);**
??????? -> 11
- QUARTER(*date*)
返回*date*對應的一年中的季度值,范圍是從 1到 4。
mysql> **SELECT QUARTER('98-04-01');**
??????? -> 2
- SECOND(*time*)
返回*time*對應的秒數, 范圍是從 0到59。
mysql> **SELECT SECOND('10:05:03');**
??????? -> 3
- SEC_TO_TIME(*seconds*)
返回被轉化為小時、 分鐘和秒數的*seconds*參數值, 其格式為 'HH:MM:SS' 或HHMMSS,具體格式根據該函數是否用在字符串或數字語境中而定。
mysql> **SELECT SEC_TO_TIME(2378);**
??????? -> '00:39:38'
mysql> **SELECT SEC_TO_TIME(2378) + 0;**
??????? -> 3938
- STR_TO_DATE(*str*,*format*)
這是DATE_FORMAT() 函數的倒轉。它獲取一個字符串 *str*和一個格式字符串*format*。若格式字符串包含日期和時間部分,則 STR_TO_DATE()返回一個 DATETIME 值, 若該字符串只包含日期部分或時間部分,則返回一個 DATE 或TIME值。
* str*所包含的日期、時間或日期時間值應該在*format*指示的格式中被給定。對于可用在*format*中的說明符,請參見DATE_FORMAT() 函數說明表。 所有其它的字符被逐字獲取,因此不會被解釋。若 *str*包含一個非法日期、時間或日期時間值,則 STR_TO_DATE()返回NULL。同時,一個非法值會引起警告。
對日期值部分的范圍檢查在[11.3.1節,“DATETIME、DATE和TIMESTAMP類型”](# "11.3.1.?The DATETIME, DATE, and TIMESTAMP Types")有詳細說明。其意義是,例如, 只要具體日期部分的范圍時從 1到 31之間,則允許一個日期中的具體日期部分大于一個月中天數值。并且,允許“零”日期或帶有0值部分的日期。
mysql> ** SELECT STR_TO_DATE('00/00/0000', '%m/%d/%Y');**
??????? -> '0000-00-00'
mysql> ** SELECT STR_TO_DATE('04/31/2004', '%m/%d/%Y');**
??????? -> '2004-04-31'
- SUBDATE(*date*,INTERVAL *expr**type*) SUBDATE(*expr*,*days*)
當被第二個參數的 INTERVAL型式調用時, SUBDATE()和DATE_SUB()的意義相同。對于有關INTERVAL參數的信息, 見有關 DATE_ADD()的討論。
mysql> ** SELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY);**
??????? -> '1997-12-02'
mysql> ** SELECT SUBDATE('1998-01-02', INTERVAL 31 DAY);**
??????? -> '1997-12-02'
第二個形式允許對*days*使用整數值。在這些情況下,它被算作由日期或日期時間表達式 *expr*中提取的天數。
mysql> ** SELECT SUBDATE('1998-01-02 12:00:00', 31);**
??????? -> '1997-12-02 12:00:00'
**注意**不能使用格式 "%X%V" 來將一個 year-week 字符串轉化為一個日期,原因是當一個星期跨越一個月份界限時,一個年和星期的組合不能標示一個唯一的年和月份。若要將year-week轉化為一個日期,則也應指定具體工作日:
mysql> ** select str_to_date('200442 Monday', '%X%V %W');**
-> 2004-10-18
- SUBTIME(*expr*,*expr2*)
SUBTIME()從*expr*中提取*expr2* ,然后返回結果。*expr* 是一個時間或日期時間表達式,而*xpr2* 是一個時間表達式。
mysql> ** SELECT SUBTIME('1997-12-31 23:59:59.999999','1 1:1:1.000002');**
??????? -> '1997-12-30 22:58:58.999997'
mysql> ** SELECT SUBTIME('01:00:00.999999', '02:00:00.999998');**
??????? -> '-00:59:59.999999'
- SYSDATE()
返回當前日期和時間值,格式為'YYYY-MM-DD HH:MM:SS' 或YYYYMMDDHHMMSS, 具體格式根據函數是否用在字符串或數字語境而定。
在一個存儲程序或觸發器中, SYSDATE()返回其執行的時間, 而非存儲成都或觸發語句開始執行的時間。這個NOW()的運作有所不同。
- TIME(*expr*)
提取一個時間或日期時間表達式的時間部分,并將其以字符串形式返回。
mysql> ** SELECT TIME('2003-12-31 01:02:03');**
??????? -> '01:02:03'
mysql> ** SELECT TIME('2003-12-31 01:02:03.000123');**
???? ???-> '01:02:03.000123'
- TIMEDIFF(*expr*,*expr2*)
TIMEDIFF() 返回起始時間 *expr*和結束時間*expr2*之間的時間。 *expr* 和*expr2*為時間或 date-and-time 表達式,兩個的類型必須一樣。?
mysql> ** SELECT TIMEDIFF('2000:01:01 00:00:00',**
??? ->???????????????? **'2000:01:01 00:00:00.000001');**
??????? -> '-00:00:00.000001'
mysql> ** SELECT TIMEDIFF('1997-12-31 23:59:59.000001',**
??? ->???????????????? **'1997-12-30 01:01:01.000002');**
??????? -> '46:58:57.999999'
- TIMESTAMP(*expr*) , TIMESTAMP(*expr*,*expr2*)
對于一個單參數,該函數將日期或日期時間表達式 *expr*作為日期時間值返回.對于兩個參數, 它將時間表達式 *expr2*添加到日期或日期時間表達式 *expr*中,將theresult作為日期時間值返回。
mysql> ** SELECT TIMESTAMP('2003-12-31');**
??????? -> '2003-12-31 00:00:00'
mysql> ** SELECT TIMESTAMP('2003-12-31 12:00:00','12:00:00');**
??????? -> '2004-01-01 00:00:00'
- TIMESTAMPADD(*interval*,*int_expr*,*datetime_expr*)
將整型表達式*int_expr*添加到日期或日期時間表達式 *datetime_expr*中。 *int_expr* 的單位被時間間隔參數給定,該參數必須是以下值的其中一個: FRAC_SECOND、SECOND、 MINUTE、 HOUR、 DAY、 WEEK、 MONTH、 QUARTER或 YEAR。
可使用所顯示的關鍵詞指定*Interval*值,或使用SQL_TSI_前綴。例如, DAY或SQL_TSI_DAY 都是正確的。
mysql> ** SELECT TIMESTAMPADD(MINUTE,1,'2003-01-02');**
??????? -> '2003-01-02 00:01:00'
mysql> ** SELECT TIMESTAMPADD(WEEK,1,'2003-01-02');**
??????? -> '2003-01-09'
- TIMESTAMPDIFF(*interval*,*datetime_expr1*,*datetime_expr2*)
返回日期或日期時間表達式*datetime_expr1*和*datetime_expr2*the 之間的整數差。其結果的單位由*interval*參數給出。*interval*的法定值同TIMESTAMPADD()函數說明中所列出的相同。
mysql> ** SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');**
??????? -> 3
mysql> ** SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01');**
??????? -> -1
- TIME_FORMAT(*time*,*format*)
其使用和 DATE_FORMAT()函數相同, 然而*format*字符串可能僅會包含處理小時、分鐘和秒的格式說明符。其它說明符產生一個NULL值或0。
若*time* value包含一個大于23的小時部分,則 %H 和 %k 小時格式說明符會產生一個大于0..23的通常范圍的值。另一個小時格式說明符產生小時值模數12。
mysql> ** SELECT TIME_FORMAT('100:00:00', '%H %k %h %I %l');**
??????? -> '100 100 04 04 4'
- TIME_TO_SEC(*time*)
返回已轉化為秒的*time*參數。
mysql> ** SELECT TIME_TO_SEC('22:23:00');**
??????? -> 80580
mysql> ** SELECT TIME_TO_SEC('00:39:38');**
??????? -> 2378
- TO_DAYS(*date*)
給定一個日期*date*, 返回一個天數 (從年份0開始的天數 )。
mysql> ** SELECT TO_DAYS(950501);**
??????? -> 728779
mysql> ** SELECT TO_DAYS('1997-10-07');**
??????? -> 729669
TO_DAYS() 不用于陽歷出現(1582)前的值,原因是當日歷改變時,遺失的日期不會被考慮在內。請參見[12.6節,“MySQL使用什么日歷?”](# "12.6.?What Calendar Is Used By MySQL?")。
請記住, MySQL使用[11.3節,“日期和時間類型”](# "11.3.?Date and Time Types")中的規則將日期中的二位數年份值轉化為四位。例如,? '1997-10-07'和 '97-10-07' 被視為同樣的日期:
mysql> ** SELECT TO_DAYS('1997-10-07'), TO_DAYS('97-10-07');**
??????? -> 729669, 729669
對于1582 年之前的日期(或許在其它地區為下一年 ), 該函數的結果實不可靠的。詳見[12.6節,“MySQL使用什么日歷?”](# "12.6.?What Calendar Is Used By MySQL?")?。
- UNIX_TIMESTAMP(), UNIX_TIMESTAMP(*date*)
若無參數調用,則返回一個Unix timestamp ('1970-01-01 00:00:00' GMT 之后的秒數) 作為無符號整數。若用*date*來調用UNIX_TIMESTAMP(),它會將參數值以'1970-01-01 00:00:00' GMT后的秒數的形式返回。*date*可以是一個DATE 字符串、一個 DATETIME字符串、一個 TIMESTAMP或一個當地時間的YYMMDD 或YYYMMDD格式的數字。
mysql> ** SELECT UNIX_TIMESTAMP();**
??????? -> 882226357
mysql> ** SELECT UNIX_TIMESTAMP('1997-10-04 22:23:00');**
??????? -> 875996580
當 UNIX_TIMESTAMP被用在 TIMESTAMP列時, 函數直接返回內部時戳值,? 而不進行任何隱含的 “string-to-Unix-timestamp”轉化。假如你向UNIX_TIMESTAMP()傳遞一個溢出日期,它會返回 0,但請注意只有基本范圍檢查會被履行 (年份從1970 到 2037, 月份從01到12,日期從? 01 到31)。
假如你想要減去 UNIX_TIMESTAMP() 列, 你或許希望刪去帶符號整數的結果。請參見[12.8節,“Cast函數和操作符”](# "12.8.?Cast Functions and Operators")。
- UTC_DATE, UTC_DATE()
返回當前 UTC日期值,其格式為 'YYYY-MM-DD' 或 YYYYMMDD,具體格式取決于函數是否用在字符串或數字語境中。?
mysql> ** SELECT UTC_DATE(), UTC_DATE() + 0;**
??? ????-> '2003-08-14', 20030814
- UTC_TIME, UTC_TIME()
返回當前 UTC 值,其格式為? 'HH:MM:SS' 或HHMMSS,具體格式根據該函數是否用在字符串或數字語境而定。
mysql> ** SELECT UTC_TIME(), UTC_TIME() + 0;**
??????? -> '18:07:53', 180753
- UTC_TIMESTAMP, UTC_TIMESTAMP()
返回當前UTC日期及時間值,格式為 'YYYY-MM-DD HH:MM:SS' 或YYYYMMDDHHMMSS,具體格式根據該函數是否用在字符串或數字語境而定。
mysql> ** SELECT UTC_TIMESTAMP(), UTC_TIMESTAMP() + 0;**
??????? -> '2003-08-14 18:08:04', 20030814180804
- WEEK(*date*[,*mode*])
該函數返回*date*對應的星期數。WEEK() 的雙參數形式允許你指定該星期是否起始于周日或周一, 以及返回值的范圍是否為從0 到53 或從1 到53。若 *mode*參數被省略,則使用default_week_format系統自變量的值。請參見[5.3.3節,“服務器系統變量”](# "5.3.3.?Server System Variables")。
以下表說明了*mode*參數的工作過程:d
<table border="1" cellpadding="0" id="table7"><tr><td> <p> <span>?</span></p></td> <td> <p><b> <span>第一天 </span></b> </p></td> <td> <p> <span>?</span></p></td> <td> <p> <span>?</span></p></td> </tr><tr><td> <p><b> <span> Mode</span></b></p></td> <td> <p><b> <span>工作日</span></b></p></td> <td> <p><b> <span>范圍</span></b></p></td> <td> <p><b> <span> Week 1 </span><span> 為第一周<span> ...</span></span></b></p></td> </tr><tr><td> <p> <span>0</span></p></td> <td> <p> <span>周日 </span></p></td> <td> <p> <span> 0-53</span></p></td> <td> <p> <span>本年度中有一個周日 </span></p></td> </tr><tr><td> <p> <span>1</span></p></td> <td> <p> <span>周一</span></p></td> <td> <p> <span> 0-53</span></p></td> <td> <p> <span>本年度中有<span>3</span>天以上 </span></p></td> </tr><tr><td> <p> <span>2</span></p></td> <td> <p> <span>周日</span></p></td> <td> <p> <span> 1-53</span></p></td> <td> <p> <span>本年度中有一個周日</span></p></td> </tr><tr><td> <p> <span>3</span></p></td> <td> <p> <span>周一</span></p></td> <td> <p> <span> 1-53</span></p></td> <td> <p> <span>本年度中有<span>3</span>天以上 </span></p></td> </tr><tr><td> <p> <span>4</span></p></td> <td> <p> <span>周日</span></p></td> <td> <p> <span> 0-53</span></p></td> <td> <p> <span>本年度中有<span>3</span>天以上</span></p></td> </tr><tr><td> <p> <span>5</span></p></td> <td> <p> <span>周一</span></p></td> <td> <p> <span> 0-53</span></p></td> <td> <p> <span>本年度中有一個周一 </span></p></td> </tr><tr><td> <p> <span>6</span></p></td> <td> <p> <span>周日</span></p></td> <td> <p> <span> 1-53</span></p></td> <td> <p> <span>本年度中有<span>3</span>天以上</span></p></td> </tr><tr><td> <p> <span>7</span></p></td> <td> <p> <span>周一</span></p></td> <td> <p> <span> 1-53</span></p></td> <td> <p> <span>本年度中有一個周一</span></p></td> </tr></table>
mysql> ** SELECT WEEK('1998-02-20');**
??????? -> 7
mysql> ** SELECT WEEK('1998-02-20',0);**
??????? -> 7
mysql> ** SELECT WEEK('1998-02-20',1);**
??????? -> 8
mysql> ** SELECT WEEK('1998-12-31',1);**
??????? -> 53
注意,假如有一個日期位于前一年的最后一周, 若你不使用2、3、6或7作為*mode*參數選擇,則MySQL返回 0:
mysql> ** SELECT YEAR('2000-01-01'), WEEK('2000-01-01',0);**
??????? -> 2000, 0
有人或許會提出意見,認為 MySQL 對于WEEK() 函數應該返回 52 ,原因是給定的日期實際上發生在1999年的第52周。我們決定返回0作為代替的原因是我們希望該函數能返回“給定年份的星期數”。這使得WEEK() 函數在同其它從日期中抽取日期部分的函數結合時的使用更加可靠。
假如你更希望所計算的關于年份的結果包括給定日期所在周的第一天,則應使用 0、2、5或 7 作為*mode*參數選擇。
mysql> ** SELECT WEEK('2000-01-01',2);**
??????? -> 52
作為選擇,可使用 YEARWEEK()函數:
mysql> ** SELECT YEARWEEK('2000-01-01');**
??????? -> 199952
mysql> ** SELECT MID(YEARWEEK('2000-01-01'),5,2);**
??????? -> '52'
- WEEKDAY(*date*)
返回*date* (0 = 周一, 1 = 周二, ... 6 = 周日)對應的工作日索引? weekday index for
mysql> ** SELECT WEEKDAY('1998-02-03 22:23:00');**
??????? -> 1
mysql> ** SELECT WEEKDAY('1997-11-05');**
??????? -> 2
- WEEKOFYEAR(*date*)
將該日期的陽歷周以數字形式返回,范圍是從1到53。它是一個兼容度函數,相當于WEEK(*date*,3)。
mysql> ** SELECT WEEKOFYEAR('1998-02-20');**
??????? -> 8
- YEAR(*date*)
返回*date*對應的年份,范圍是從1000到9999。
mysql> ** SELECT YEAR('98-02-03');**
??????? -> 1998
- YEARWEEK(*date*), YEARWEEK(*date*,*start*)
返回一個日期對應的年或周。*start*參數的工作同 *start*參數對 WEEK()的工作相同。結果中的年份可以和該年的第一周和最后一周對應的日期參數有所不同。
mysql> ** SELECT YEARWEEK('1987-01-01');**
??????? -> 198653
注意,周數和WEEK()函數隊可選參數0或 1可能會返回的(0) w有所不同,原因是此時 WEEK() 返回給定年份的語境中的周。
-
~~~
-> '1997-10-07'
~~~
### 12.6.?MySQL使用什么日歷?
MySQL 使用通常所說的 *proleptic *陽歷*。*
每個將日歷由朱利安改為陽歷的國家在改變日歷期間都不得不刪除至少10天。 為了了解其運作,讓我們看看1582年10月,這是由朱利安日歷轉換為陽歷的第一次:
<table border="1" cellpadding="0" id="table8"><tr><td> <p> <span>周一</span></p></td> <td> <p> <span>周二</span></p></td> <td> <p> <span>周三</span></p></td> <td> <p> <span>周四</span></p></td> <td> <p> <span>周五</span></p></td> <td> <p> <span>周六</span></p></td> <td> <p> <span>周日</span></p></td> </tr><tr><td> <p> <span>1</span></p></td> <td> <p> <span>2</span></p></td> <td> <p> <span>3</span></p></td> <td> <p> <span>4</span></p></td> <td> <p> <span>15</span></p></td> <td> <p> <span>16</span></p></td> <td> <p> <span>17</span></p></td> </tr><tr><td> <p> <span>18</span></p></td> <td> <p> <span>19</span></p></td> <td> <p> <span>20</span></p></td> <td> <p> <span>21</span></p></td> <td> <p> <span>22</span></p></td> <td> <p> <span>23</span></p></td> <td> <p> <span>24</span></p></td> </tr><tr><td> <p> <span>25</span></p></td> <td> <p> <span>26</span></p></td> <td> <p> <span>27</span></p></td> <td> <p> <span>28</span></p></td> <td> <p> <span>29</span></p></td> <td> <p> <span>30</span></p></td> <td> <p> <span>31</span></p></td> </tr></table>
在10月4 日到10月15日之間的日期為空白。這個中斷被稱為*接入*。接入前的日期均使用朱利安日歷, 而接入后的日期均使用陽歷。接入期間的日期是不存在的。
當一個用于日期的日歷并為得到實際使用時被稱為 *proleptic*。因此, 若我們假設從來沒有接入期的存在,而陽歷歷法則始終被使用,我們會有一個預期的陽歷 。這就是MySQL 所使用的,正如標準SQL所要求的。 鑒于這個原因,作為MySQL DATE 或 DATETIME值而被儲存的接入前的日期必須調整這個差異。我們必須明白,接入的發生時間在不同的國家有所不同,而接入的時間越晚,遺失的日期越多。例如,在大不列顛, 接入發生在 1752年,這時9月2日,周三后的第二天為9月14日,周二; 俄羅斯結束使用朱利安日歷的時間為1918年,接入過程中遺失天數為 13天, 根據陽歷,其普遍被稱為“10月革命”的發生時間實際上是11月。
### 12.7.?全文搜索功能
[ 12.7.1. 布爾全文搜索](#)[ 12.7.2. 全文搜索帶查詢擴展](#)[ 12.7.3. 全文停止字](#)[ 12.7.4. 全文限定條件](#)[ 12.7.5. 微調MySQL全文搜索](#)
- [MATCH (col1,col2,...) AGAINST (expr [IN BOOLEAN MODE | WITH QUERY EXPANSION]) ]()
MySQL支持全文索引和搜索功能。MySQL中的全文索引類型FULLTEXT的索引。? FULLTEXT 索引僅可用于 MyISAM 表;他們可以從CHAR、 VARCHAR或TEXT列中作為CREATE TABLE語句的一部分被創建,或是隨后使用ALTER TABLE 或 CREATE INDEX被添加。對于較大的數據集,將你的資料輸入一個沒有FULLTEXT索引的表中,然后創建索引, 其速度比把資料輸入現有FULLTEXT索引的速度更為快。
關于全文搜索的限制列表,請參見 [ 12.7.4節,“全文限定條件”](# "12.7.4.?Full-Text Restrictions").
全文搜索同MATCH()函數一起執行。?
~~~
mysql> CREATE TABLE articles (
~~~
~~~
??? ->?? id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
~~~
~~~
??? ->?? title VARCHAR(200),
~~~
~~~
??? ->?? body TEXT,
~~~
~~~
??? ->?? FULLTEXT (title,body)
~~~
~~~
??? -> );
~~~
~~~
Query OK, 0 rows affected (0.00 sec)
~~~
~~~
?
~~~
~~~
mysql> INSERT INTO articles (title,body) VALUES
~~~
~~~
??? -> ('MySQL Tutorial','DBMS stands for DataBase ...'),
~~~
~~~
??? -> ('How To Use MySQL Well','After you went through a ...'),
~~~
~~~
??? -> ('Optimizing MySQL','In this tutorial we will show ...'),
~~~
~~~
??? -> ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
~~~
~~~
??? -> ('MySQL vs. YourSQL','In the following database comparison ...'),
~~~
~~~
??? -> ('MySQL Security','When configured properly, MySQL ...');
~~~
~~~
Query OK, 6 rows affected (0.00 sec)
~~~
~~~
Records: 6? Duplicates: 0 ?Warnings: 0
~~~
~~~
?
~~~
~~~
mysql> SELECT * FROM articles
~~~
~~~
??? -> WHERE MATCH (title,body) AGAINST ('database');
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
| id | title???????????? | body???????????????????????????????????? |
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
|? 5 | MySQL vs. YourSQL | In the following database comparison ... |
~~~
~~~
|? 1 | MySQL Tutorial??? | DBMS stands for DataBase ...???????????? |
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
2 rows in set (0.00 sec)
~~~
MATCH()函數對于一個字符串執行資料庫內的自然語言搜索。一個資料庫就是1套1個或2個包含在FULLTEXT內的列。搜索字符串作為對AGAINST()的參數而被給定。對于表中的每一行, MATCH() 返回一個相關值,即, 搜索字符串和 MATCH()表中指定列中該行文字之間的一個相似性度量。
在默認狀態下, 搜索的執行方式為不區分大小寫方式。然而,你可以通過對編入索引的列使用二進制排序方式執行區分大小寫的全文搜索。例如,可以向一個使用latin1字符集的列給定latin1_bin 的排序方式,對于全文搜索區分大小寫。
如上述所舉例子,當MATCH()被用在一個WHERE 語句中時,相關值是非負浮點數。零相關的意思是沒有相似性。相關性的計算是基于該行中單詞的數目, 該行中獨特子的數目,資料庫中單詞的總數,以及包含特殊詞的文件(行)數目。
對于自然語言全文搜索,要求MATCH() 函數中命名的列和你的表中一些FULLTEXT索引中包含的列相同。對于前述問訊, 注意,MATCH()函數(題目及全文)中所命名的列和文章表的FULLTEXT索引中的列相同。若要分別搜索題目和全文,應該對每個列創建FULLTEXT索引。
或者也可以運行布爾搜索或使用查詢擴展進行搜索。關于這些搜索類型的說明見[12.7.1節,“布爾全文搜索”](# "12.7.1.?Boolean Full-Text Searches")和[12.7.2節,“全文搜索帶查詢擴展”](# "12.7.2.?Full-Text Searches with Query Expansion")。
上面的例子基本上展示了怎樣使用返回行的相關性順序漸弱的MATCH()函數。而下面的例子則展示了怎樣明確地檢索相關值。返回行的順序是不定的,原因是? SELECT 語句不包含 WHERE或ORDER BY 子句:
~~~
mysql> SELECT id, MATCH (title,body) AGAINST ('Tutorial')
~~~
~~~
??? -> FROM articles;
~~~
~~~
+----+-----------------------------------------+
~~~
~~~
| id | MATCH (title,body) AGAINST ('Tutorial') |
~~~
~~~
+----+-----------------------------------------+
~~~
~~~
|? 1 |??????????????????????? 0.65545833110809 |
~~~
~~~
|? 2 |?????????????????????????????????????? 0 |
~~~
~~~
|? 3 |??????????????????????? 0.66266459226608 |
~~~
~~~
|? 4 |?????????????????????????????????????? 0 |
~~~
~~~
|? 5 |?????????????????????????????????????? 0 |
~~~
~~~
|? 6 |?????????????????????????????????????? 0 |
~~~
~~~
+----+-----------------------------------------+
~~~
~~~
6 rows in set (0.00 sec)
~~~
下面的例子則更加復雜。詢問返回相關值,同時對行按照相關性漸弱的順序進行排序。為實現這個結果,你應該兩次指定 MATCH(): 一次在 SELECT 列表中而另一次在 WHERE子句中。這不會引起額外的內務操作,原因是MySQL 優化程序注意到兩個MATCH()調用是相同的,從而只會激活一次全文搜索代碼。?
~~~
mysql> SELECT id, body, MATCH (title,body) AGAINST
~~~
~~~
??? -> ('Security implications of running MySQL as root') AS score
~~~
~~~
??? -> FROM articles WHERE MATCH (title,body) AGAINST
~~~
~~~
??? -> ('Security implications of running MySQL as root');
~~~
~~~
+----+-------------------------------------+-----------------+
~~~
~~~
| id | body??????????????????????????????? | score?????????? |
~~~
~~~
+----+-------------------------------------+-----------------+
~~~
~~~
|? 4 | 1. Never run mysqld as root. 2. ... | 1.5219271183014 |
~~~
~~~
|? 6 | When configured properly, MySQL ... | 1.3114095926285 |
~~~
~~~
+----+-------------------------------------+-----------------+
~~~
~~~
2 rows in set (0.00 sec)
~~~
表中有2行(0.00 秒)
MySQL FULLTEXT 執行將任何單字字符原形 (字母、數字和下劃線部分)的序列視為一個單詞。這個序列或許也包含單引號 ('),但在一行中不會超過一個。 這意味著 aaa'bbb 會被視為一個單詞,而 aaa''bbb則被視為2個單詞。位于單詞之前或其后的單引號會被FULLTEXT分析程序去掉; 'aaa'bbb' 會變成?? aaa'bbb。
FULLTEXT分析程序會通過尋找某些分隔符來確定單詞的起始位置和結束位置,例如' ' (間隔符號)、 , (逗號)以及 . (句號 )。假如單詞沒有被分隔符分開,(例如在中文里 ), 則 FULLTEXT 分析程序不能確定一個詞的起始位置和結束位置。為了能夠在這樣的語言中向FULLTEXT 索引添加單詞或其它編入索引的術語,你必須對它們進行預處理,使其被一些諸如"之類的任意分隔符分隔開。
一些詞在全文搜索中會被忽略:?
- 任何過于短的詞都會被忽略。 全文搜索所能找到的詞的默認最小長度為 4個字符。
- 停止字中的詞會被忽略。禁用詞就是一個像“the” 或“some” 這樣過于平常而被認為是不具語義的詞。存在一個內置的停止字, 但它可以通過用戶自定義列表被改寫。請參見[12.7.5節,“微調MySQL全文搜索”](# "12.7.5.?Fine-Tuning MySQL Full-Text Search")。
默認的停止字在[12.7.3節,“全文停止字”](# "12.7.3.?Full-Text Stopwords")中被給出。默認的最小單詞長度和 停止字可以被改變,如[12.7.5節,“微調MySQL全文搜索”](# "12.7.5.?Fine-Tuning MySQL Full-Text Search")中所述。
詞庫和詢問中每一個正確的單詞根據其在詞庫和詢問中的重要性而被衡量。? 通過這種方式,一個出現在許多文件中的單詞具有較低的重要性(而且甚至很多單詞的重要性為零),原因是在這個特別詞庫中其語義價值較低。反之,假如這個單詞比較少見,那么它會得到一個較高的重要性。然后單詞的重要性被組合,從而用來計算該行的相關性。?
這項技術最適合同大型詞庫一起使用 (事實上, 此時它經過仔細的調整 )。對于很小的表,單詞分布并不能充分反映它們的語義價值, 而這個模式有時可能會產生奇特的結果。例如, 雖然單詞 “MySQL” 出現在文章表中的每一行,但對這個詞的搜索可能得不到任何結果:
mysql> ** SELECT * FROM articles**
??? -> ** WHERE MATCH (title,body) AGAINST ('MySQL');**
找不到搜索的詞(0.00 秒)
這個搜索的結果為空,原因是單詞 “MySQL” 出現在至少全文的50%的行中。 因此, 它被列入停止字。對于大型數據集,使用這個操作最合適不過了----一個自然語言問詢不會從一個1GB 的表每隔一行返回一次。對于小型數據集,它的用處可能比較小。
一個符合表中所有行的內容的一半的單詞查找相關文檔的可能性較小。事實上, 它更容易找到很多不相關的內容。我們都知道,當我們在因特網上試圖使用搜索引擎尋找資料的時候,這種情況發生的頻率頗高。可以推論,包含該單詞的行因*其所在特別數據集 *而被賦予較低的語義價值。 一個給定的詞有可能在一個數據集中擁有超過其50%的域值,而在另一個數據集卻不然。?
當你第一次嘗試使用全文搜索以了解其工作過程時,這個50% 的域值提供重要的蘊涵操作:若你創建了一個表,并且只將文章的1、2行插入其中, 而文中的每個單詞在所有行中出現的機率至少為? 50% 。那么結果是你什么也不會搜索到。一定要插入至少3行,并且多多益善。需要繞過該50% 限制的用戶可使用布爾搜索代碼;見[12.7.1節,“布爾全文搜索”](# "12.7.1.?Boolean Full-Text Searches")。
### 12.7.1.?布爾全文搜索
利用IN BOOLEAN MODE修改程序, MySQL 也可以執行布爾全文搜索:
~~~
mysql> SELECT * FROM articles WHERE MATCH (title,body)
~~~
~~~
??? -> AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
~~~
~~~
+----+-----------------------+-------------------------------------+
~~~
~~~
| id | title???????????????? | body??????????????????????????????? |
~~~
~~~
+----+-----------------------+-------------------------------------+
~~~
~~~
|? 1 | MySQL Tutorial??????? | DBMS stands for DataBase ...??????? |
~~~
~~~
|? 2 | How To Use MySQL Well | After you went through a ...??????? |
~~~
~~~
|? 3 | Optimizing MySQL????? | In this tutorial we will show ...?? |
~~~
~~~
|? 4 | 1001 MySQL Tricks???? | 1. Never run mysqld as root. 2. ... |
~~~
~~~
|? 6 | MySQL Security??????? | When configured properly, MySQL ... |
~~~
~~~
+----+-----------------------+-------------------------------------+
~~~
這個問詢檢索所有包含單詞“MySQL”的行,但*不*檢索包含單詞“YourSQL”的行。
布爾全文搜索具有以下特點:
- 它們不使用 50% 域值。.
- 它們不會按照相關性漸弱的順序將行進行分類。你可以從上述問詢結果中看到這一點:相關性最高的行是一個包含兩個“MySQL” 的行,但它被列在最后的位置,而不是開頭位置。
- 即使沒有FULLTEXT,它們仍然可以工作,盡管這種方式的搜索執行的速度非常之慢。
- 最小單詞長度全文參數和最大單詞長度全文參數均適用。
- 停止字適用。
布爾全文搜索的性能支持以下操作符:?
- +
一個前導的加號表示該單詞*必須* 出現在返回的每一行的開頭位置。
- -
一個前導的減號表示該單詞*一定不能*出現在任何返回的行中。
- (無操作符)
在默認狀態下(當沒有指定 + 或–的情況下),該單詞可有可無,但含有該單詞的行等級較高。這和MATCH() ... AGAINST()不使用IN BOOLEAN MODE修改程序時的運作很類似。??
- > <
這兩個操作符用來改變一個單詞對賦予某一行的相關值的影響。 > 操作符增強其影響,而 <操作符則減弱其影響。請參見下面的例子。?
- ( )
括號用來將單詞分成子表達式。括入括號的部分可以被嵌套。
- ~
一個前導的代字號用作否定符, 用來否定單詞對該行相關性的影響。 這對于標記“noise(無用信息)”的單詞很有用。包含這類單詞的行較其它行等級低,但因其可能會和-號同時使用,因而不會在任何時候都派出所有無用信息行。
- *
星號用作截斷符。于其它符號不同的是,它應當被*追加*到要截斷的詞上。
- "
一個被括入雙引號的短語 (‘"’) 只和*字面上*包含該短語*輸入格式*的行進行匹配。全文引擎將短語拆分成單詞,在FULLTEXT索引中搜索該單詞。?? 非單詞字符不需要嚴密的匹配:短語搜索只要求符合搜索短語包含的單詞且單詞的排列順序相同的內容。例如, "test phrase" 符合 "test, phrase"。
若索引中不存在該短語包含的單詞,則結果為空。例如,若所有單詞都是禁用詞,或是長度都小于編入索引單詞的最小長度,則結果為空。
以下例子展示了一些使用布爾全文符號的搜索字符串:
- 'apple banana'
尋找包含至少兩個單詞中的一個的行。
- '+apple +juice'
尋找兩個單詞都包含的行。
- '+apple macintosh'
尋找包含單詞“apple”的行,若這些行也包含單詞“macintosh”, 則列為更高等級。
- '+apple -macintosh'
尋找包含單詞“apple” 但不包含單詞 “macintosh”的行。
- '+apple +(>turnover <strudel)'
尋找包含單詞“apple”和“turnover” 的行,或包含“apple” 和“strudel”的行 (無先后順序),然而包含 “apple turnover”的行較包含“apple strudel”的行排列等級更為高。
- 'apple*'
尋找包含“apple”、“apples”、“applesauce”或“applet”的行。
- '"some words"'
尋找包含原短語“some words”的行 (例如,包含“some words of wisdom” 的行,而非包含? “some noise words”的行)。注意包圍詞組的‘"’ 符號是界定短語的操作符字符。它們不是包圍搜索字符串本身的引號。
### 12.7.2.?全文搜索帶查詢擴展
全文搜索支持查詢擴展功能 (特別是其多變的“盲查詢擴展功能” )。若搜索短語的長度過短, 那么用戶則需要依靠全文搜索引擎通常缺乏的內隱知識進行查詢。這時,查詢擴展功能通常很有用。例如, 某位搜索 “database” 一詞的用戶,可能認為“MySQL”、“Oracle”、“DB2” and “RDBMS”均為符合 “databases”的項,因此都應被返回。這既為內隱知識。
在下列搜索短語后添加WITH QUERY EXPANSION,激活盲查詢擴展功能(即通常所說的自動相關性反饋)。它將執行兩次搜索,其中第二次搜索的搜索短語是同第一次搜索時找到的少數頂層文件連接的原始搜索短語。這樣,假如這些文件中的一個 含有單詞 “databases” 以及單詞 “MySQL”, 則第二次搜索會尋找含有單詞“MySQL” 的文件,即使這些文件不包含單詞 “database”。下面的例子顯示了這個不同之處:
~~~
mysql> SELECT * FROM articles
~~~
~~~
??? -> WHERE MATCH (title,body) AGAINST ('database');
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
| id | title???????????? | body???????????????????????????????????? |
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
|? 5 | MySQL vs. YourSQL | In the following database comparison ... |
~~~
~~~
|? 1 | MySQL Tutorial??? | DBMS stands for DataBase ...???????????? |
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
2 rows in set (0.00 sec)
~~~
~~~
?
~~~
~~~
mysql> SELECT * FROM articles
~~~
~~~
??? -> WHERE MATCH (title,body)
~~~
~~~
??? -> AGAINST ('database' WITH QUERY EXPANSION);
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
| id | title???????????? | body???????????????????????????????????? |
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
|? 1 | MySQL Tutorial??? | DBMS stands for DataBase ...???????????? |
~~~
~~~
|? 5 | MySQL vs. YourSQL | In the following database comparison ... |
~~~
~~~
|? 3 | Optimizing MySQL? | In this tutorial we will show ...??????? |
~~~
~~~
+----+-------------------+------------------------------------------+
~~~
~~~
3 rows in set (0.00 sec)
~~~
另一個例子是Georges Simenon 搜索關于Maigret的書籍, 這個用戶不確定“Maigret”一詞的拼法。若不使用查詢擴展而搜索“Megre and the reluctant witnesses” 得到的結果只能是的“Maigret and the Reluctant Witnesses” 。 而帶有查詢擴展的搜索會在第二遍得到帶有“Maigret”一詞的所有書名。
**注釋**:? 盲查詢擴展功能很容易返回非相關文件而增加無用信息,因此只有在查詢一個長度很短的短語時才有必要使用這項功能。
### 12.7.3.?全文停止字
以下表列出了默認的全文停止字:?
| a's | able | about | above | according |
|-----|-----|-----|-----|-----|
| accordingly | across | actually | after | afterwards |
| again | against | ain't | all | allow |
| allows | almost | alone | along | already |
| also | although | always | am | among |
| amongst | an | and | another | any |
| anybody | anyhow | anyone | anything | anyway |
| anyways | anywhere | apart | appear | appreciate |
| appropriate | are | aren't | around | as |
| aside | ask | asking | associated | at |
| available | away | awfully | be | became |
| because | become | becomes | becoming | been |
| before | beforehand | behind | being | believe |
| below | beside | besides | best | better |
| between | beyond | both | brief | but |
| by | c'mon | c's | came | can |
| can't | cannot | cant | cause | causes |
| certain | certainly | changes | clearly | co |
| com | come | comes | concerning | consequently |
| consider | considering | contain | containing | contains |
| corresponding | could | couldn't | course | currently |
| definitely | described | despite | did | didn't |
| different | do | does | doesn't | doing |
| don't | done | down | downwards | during |
| each | edu | eg | eight | either |
| else | elsewhere | enough | entirely | especially |
| et | etc | even | ever | every |
| everybody | everyone | everything | everywhere | ex |
| exactly | example | except | far | few |
| fifth | first | five | followed | following |
| follows | for | former | formerly | forth |
| four | from | further | furthermore | get |
| gets | getting | given | gives | go |
| goes | going | gone | got | gotten |
| greetings | had | hadn't | happens | hardly |
| has | hasn't | have | haven't | having |
| he | he's | hello | help | hence |
| her | here | here's | hereafter | hereby |
| herein | hereupon | hers | herself | hi |
| him | himself | his | hither | hopefully |
| how | howbeit | however | i'd | i'll |
| i'm | i've | ie | if | ignored |
| immediate | in | inasmuch | inc | indeed |
| indicate | indicated | indicates | inner | insofar |
| instead | into | inward | is | isn't |
| it | it'd | it'll | it's | its |
| itself | just | keep | keeps | kept |
| know | knows | known | last | lately |
| later | latter | latterly | least | less |
| lest | let | let's | like | liked |
| likely | little | look | looking | looks |
| ltd | mainly | many | may | maybe |
| me | mean | meanwhile | merely | might |
| more | moreover | most | mostly | much |
| must | my | myself | name | namely |
| nd | near | nearly | necessary | need |
| needs | neither | never | nevertheless | new |
| next | nine | no | nobody | non |
| none | noone | nor | normally | not |
| nothing | novel | now | nowhere | obviously |
| of | off | often | oh | ok |
| okay | old | on | once | one |
| ones | only | onto | or | other |
| others | otherwise | ought | our | ours |
| ourselves | out | outside | over | overall |
| own | particular | particularly | per | perhaps |
| placed | please | plus | possible | presumably |
| probably | provides | que | quite | qv |
| rather | rd | re | really | reasonably |
| regarding | regardless | regards | relatively | respectively |
| right | said | same | saw | say |
| saying | says | second | secondly | see |
| seeing | seem | seemed | seeming | seems |
| seen | self | selves | sensible | sent |
| serious | seriously | seven | several | shall |
| she | should | shouldn't | since | six |
| so | some | somebody | somehow | someone |
| something | sometime | sometimes | somewhat | somewhere |
| soon | sorry | specified | specify | specifying |
| still | sub | such | sup | sure |
| t's | take | taken | tell | tends |
| th | than | thank | thanks | thanx |
| that | that's | thats | the | their |
| theirs | them | themselves | then | thence |
| there | there's | thereafter | thereby | therefore |
| therein | theres | thereupon | these | they |
| they'd | they'll | they're | they've | think |
| third | this | thorough | thoroughly | those |
| though | three | through | throughout | thru |
| thus | to | together | too | took |
| toward | towards | tried | tries | truly |
| try | trying | twice | two | un |
| under | unfortunately | unless | unlikely | until |
| unto | up | upon | us | use |
| used | useful | uses | using | usually |
| value | various | very | via | viz |
| vs | want | wants | was | wasn't |
| way | we | we'd | we'll | we're |
| we've | welcome | well | went | were |
| weren't | what | what's | whatever | when |
| whence | whenever | where | where's | whereafter |
| whereas | whereby | wherein | whereupon | wherever |
| whether | which | while | whither | who |
| who's | whoever | whole | whom | whose |
| why | will | willing | wish | with |
| within | without | won't | wonder | would |
| would | wouldn't | yes | yet | you |
| you'd | you'll | you're | you've | your |
| yours | yourself | yourselves | zero | ? |
### 12.7.4.?全文限定條件
- 全文搜索只適用于 MyISAM 表。
- 全文搜索可以同大多數多字節字符集一起使用。Unicode屬于例外情況;? 可使用utf8 字符集 , 而非ucs2字符集。
- 諸如漢語和日語這樣的表意語言沒有自定界符。因此, FULLTEXT分析程序*不能確定在這些或其它的這類語言中詞的起始和結束的位置。*其隱含操作及該問題的一些工作區在[12.7節,“全文搜索功能”](# "12.7.?Full-Text Search Functions")有詳細論述。
- 若支持在一個單獨表中使用多字符集,則所有 FULLTEXT索引中的列 必須使用同樣的字符集和庫。
- MATCH()列列表必須同該表中一些 FULLTEXT索引定義中的列列表完全符合,除非MATCH()在IN BOOLEAN MODE。
- 對AGAINST() 的參數必須是一個常數字符串。?
### 12.7.5.?微調MySQL全文搜索
MySQL的全文搜索容量幾乎不具有用戶調節參數。假如你擁有一個 MySQL源分布,你就能對全文搜索性能行使更多控制,原因是一些變化需要源代碼修改。請參見[2.8節,“使用源碼分發版安裝MySQL”](# "2.8.?MySQL Installation Using a Source Distribution")。
注意,為了更加有效,需要對全文搜索謹慎調節。實際上,在大多數情況下修改默認性能只能降低其性能。* 除非你知道自己在做什么,否則不要改變 MySQL源。? *
下述的大多數全文變量必須在服務器啟動時被設置。為了改變它們,還要重新啟動服務器;在服務器正在運行期間,他們不會被改變。?
一些變量的改變需要你重建表中的 FULLTEXT 索引。本章結尾部分給出了其有關操作說明。
- ft_min_word_len and ft_max_word_len系統自變量規定了被編入索引單詞的最小長度和最大長度。(見[5.3.3節,“服務器系統變量”](# "5.3.3.?Server System Variables").) 默認的最小值為四個字符;默認的最大值取決于使用的 MySQL 版本。假如你改變任意一個值,那么你必須重建你的 FULLTEXT索引。 例如,若你希望一個3字符的單詞變為可查找項,則可以通過將以下行移動到一個供選擇文件里,從而設置 ft_min_word_len 變量:
·??????????????? [mysqld]
·??????????????? ft_min_word_len=3
然后重新啟動服務器,重建你的 FULLTEXT索引。同時還要特別注意該表后面的說明中的關于**myisamchk**的注釋。
- 若要覆蓋默認停止字,則可設置 ft_stopword_file 系統變量。 (見[5.3.3節,“服務器系統變量”](# "5.3.3.?Server System Variables"))。 變量值應為包含停止字的文件路徑名, 或是用來截止禁用詞過濾的空字符串。在改變了這個變量的值或禁用詞文件的內容后, 重建你的 FULLTEXT索引。
停止字是自由形態的,換言之,你可使用任何諸如newline、 space或comma這樣的非字母數字字符來分隔禁用詞。 下劃線字符(_) 和被視為單詞的一部分的單引號 (')例外。停止字字符集為服務器默認字符集;見[10.3.1節,“服務器字符集和校對”](# "10.3.1.?Server Character Set and Collation").
- ?自然語言查詢的50%閾值由所選擇的特別權衡方案所決定。若要阻止它,myisam/ftdefs.h 中尋找以下行:
·??????????????? #define GWS_IN_USE GWS_PROB
將該行改為:
#define GWS_IN_USE GWS_FREQ
然后重新編譯 MySQL。此時不需要重建索引。注釋:這樣做你會*嚴重的*By 降低 MySQL為MATCH()函數提供合適的相關值得能力。假如你爭得需要搜索這樣的普通詞,而使用IN BOOLEAN MODE代替的效果更好,因為它不遵循 50% 閾值。
- 要改變用于布爾全文搜索的操作符,設置 ft_boolean_syntax 系統變量。 這個變量也可以在服務器運行時被改變,但你必須有SUPER 特權才能這么做。在這種情況下不需要重建索引。 見[5.3.3節,“服務器系統變量”](# "5.3.3.?Server System Variables"), 它向我們說明了怎樣使用這個變量的規則。
假如你改變了影響索引的全文變量 (ft_min_word_len、 ft_max_word_len或ft_stopword_file),或假如你改變了禁用詞文件本身,則你必須在改變和重新啟動服務器后重建你的 FULLTEXT索引。這時,要重建索引, 只需進行一個 QUICK 修理操作:?
mysql> ** REPAIR TABLE *tbl_name* QUICK;**
注意,假如你使用? **myisamchk**來執行一項修改表索引的操作 (諸如修理或分析 ), 則使用最小單詞長度和最大單詞長度以及停止字的默認全文參數值重建FULLTEXT索引,除非你已另外指定。這會導致問詢失敗。
發生這個問題的原因是只有服務器認識這些參數。它們的存儲位置不在? MyISAM 索引文件中。若你已經修改了最小單詞長度或最大單詞長度或服務器中的停止字,為避免這個問題,為你對**mysqld**所使用的**myisamchk**指定同樣的 ft_min_word_len、 ft_max_word_len和ft_stopword_file值。例如,假如你已經將最小單詞長度設置為 3, 則你可以這樣修改一個帶有**myisamchk**的表:
shell> ** myisamchk --recover --ft_min_word_len=3 *tbl_name*.MYI**
為保證 **myisamchk** 及服務器對全文參數使用相同的值, 可將每一項都放在供選文件中的 [mysqld]和 [myisamchk] 部分:
[mysqld]
ft_min_word_len=3
?
[myisamchk]
ft_min_word_len=3
使用 REPAIR TABLE、 ANALYZE TABLE、OPTIMIZE TABLE或ALTER TABLE來代替使用 **myisamchk** 。這些語句通過服務器來執行,服務器知道使用哪個全文參數值更加合適。
### 12.8.?Cast函數和操作符
- BINARY
BINARY操作符將后面的字符串拋給一個二進制字符串。這是一種簡單的方式來促使逐字節而不是逐字符的進行列比較。這使得比較區分大小寫,即使該列不被定義為 BINARY或 BLOB。BINARY也會產生結尾空白,從而更加顯眼。
mysql> **SELECT 'a' = 'A';**
??????? -> 1
mysql> **SELECT BINARY 'a' = 'A';**
??????? -> 0
mysql> **SELECT 'a' = 'a ';**
??????? -> 1
mysql> **SELECT BINARY 'a' = 'a ';**
??????? -> 0
BINARY影響整個比較;它可以在任何操作數前被給定,而產生相同的結果。
BINARY *str*是CAST(*str* AS BINARY)的縮略形式。
注意,在一些語境中,假如你將一個編入索引的列派給BINARY, MySQL 將不能有效使用這個索引。
假如你想要將一個 BLOB值或其它二進制字符串進行區分大小寫的比較,你可利用二進制字符串沒有字符集這一事實實現這個目的,這樣就不會有文書夾的概念。為執行一個區分大小寫的比較,可使用? CONVERT()函數將一個字符串值轉化為一個不區分大小寫的字符集。其結果為一個非二進制字符串,因此 LIKE 操作也不會區分大小寫:
SELECT 'A' LIKE CONVERT(*blob_col* USING latin1) FROM *tbl_name*;
若要使用一個不同的字符集, 替換其在上述語句中的latin1名。
CONVERT()一般可用于比較出現在不同字符集中的字符串。
- CAST(*expr* AS *type*), CONVERT(*expr*,*type*) , CONVERT(*expr* USING *transcoding_name*)
CAST() 和CONVERT() 函數可用來獲取一個類型的值,并產生另一個類型的值。
這個*類型* 可以是以下值其中的 一個:?
- BINARY[(*N*)]
- CHAR[(*N*)]
- DATE
- DATETIME
- DECIMAL
- SIGNED [INTEGER]
- TIME
- UNSIGNED [INTEGER]
BINARY 產生一個二進制字符串。關于它怎樣影響比較結果的說明見本章中 BINARY操作符項。
假如給定了隨意長度*N*,則 BINARY[*N*] 使 cast使用該參數的不多于 *N*個字節。同樣的, CHAR[*N*]會使 cast 使用該參數的不多于*N*個字符。
CAST() and CONVERT(... USING ...) 是標準 SQL語法。CONVERT()的非USING 格式是ofis ODBC語法。
帶有USING的CONVERT() 被用來在不同的字符集之間轉化數據。在 MySQL中, 自動譯碼名和相應的字符集名稱相同。例如。 這個語句將服務器的默認字符集中的字符串 'abc'轉化為utf8字符集中相應的字符串:?
SELECT CONVERT('abc' USING utf8);
當你想要在一個CREATE ... SELECT 語句中創建一個特殊類型的列,則cast函數會很有用:
CREATE TABLE new_table SELECT CAST('2000-01-01' AS DATE);
該函數也用于ENUM 列按詞法順序的排序。通常ENUM列的排序在使用內部數值時發生。將這些值按照詞法順序派給 CHAR 結果:
SELECT *enum_col* FROM *tbl_name* ORDER BY CAST(*enum_col* AS CHAR);
CAST(*str* AS BINARY)和BINARY *str*相同*。* CAST(*expr* AS CHAR) 將表達式視為一個帶有默認字符集的字符串。
若用于一個諸如 CONCAT('Date: ',CAST(NOW() AS DATE))這樣的比較復雜的表達式的一部分,CAST()也會改變結果。
你不應在不同的格式中使用 CAST() 來析取數據,但可以使用諸如LEFT() 或 EXTRACT() 的樣的字符串函數來代替。請參見[12.5節,“日期和時間函數”](# "12.5.?Date and Time Functions")。
若要在數值語境中將一個字符串派給一個數值, 通常情況下,除了將字符串值作為數字使用外,你不需要做任何事:
mysql> **SELECT 1+'1';**
?????? -> 2
若要在一個字符串語境中使用一個數字,該數字會被自動轉化為一個BINARY 字符串。
mysql> **SELECT CONCAT('hello you ',2);**
??????? -> 'hello you 2'
MySQL 支持帶符號和無符號的64比特值的運算。若你正在使用數字操作符? (如 +) 而其中一個操作數為無符號整數,則結果為無符號。可使用SIGNED 和UNSIGNED cast 操作符來覆蓋它。將運算分別派給帶符號或無符號64比特整數。
mysql> **SELECT CAST(1-2 AS UNSIGNED)**
??????? -> 18446744073709551615
mysql> **SELECT CAST(CAST(1-2 AS UNSIGNED) AS SIGNED);**
??????? -> -1
注意,假如任意一個操作數為一個浮點值,則結果為一個浮點值, 且不會受到上述規則影響 (關于這一點, DECIMAL 列值被視為浮點值)。
mysql> **SELECT CAST(1 AS UNSIGNED) - 2.0;**
??????? -> -1.0
若你在一個算術運算中使用了一個字符串,它會被轉化為一個浮點數。?
### 12.9.?其他函數
[ 12.9.1. 位函數](#)[ 12.9.2. 加密函數](#)[ 12.9.3. 信息函數](#)[ 12.9.4. 其他函數](#)
### 12.9.1.?位函數
對于比特運算,MySQL 使用 BIGINT (64比特) 算法,因此這些操作符的最大范圍是 64 比特。
- |
Bitwise OR:
mysql> **SELECT 29 | 15;**
??????? -> 31
其結果為一個64比特無符號整數。
- &
Bitwise AND:
mysql> **SELECT 29 & 15;**
??????? -> 13
其結果為一個64比特無符號整數。
- ^
Bitwise XOR:
mysql> **SELECT 1 ^ 1;**
??????? -> 0
mysql> **SELECT 1 ^ 0;**
??????? -> 1
mysql> **SELECT 11 ^ 3;**
??????? -> 8
結果為一個64比特無符號整數。
- <<
把一個longlong (BIGINT)數左移兩位。
mysql> **SELECT 1 << 2;**
??????? -> 4
其結果為一個64比特無符號整數。
- >>
把一個longlong (BIGINT)數右移兩位。
mysql> **SELECT 4 >> 2;**
??????? -> 1
其結果為一個64比特無符號整數。
- ~
反轉所有比特。
mysql> **SELECT 5 & ~1;**
??????? -> 4
其結果為一個64比特無符號整數。
- BIT_COUNT(*N*)
返回參數*N*中所設置的比特數
mysql> **SELECT BIT_COUNT(29);**
??????? -> 4
### 12.9.2.?加密函數
本節介紹了加密和加密值。若你想要儲存一些由可能包含任意字節值的加密函數返回的結果,使用BLOB列而不是 CHAR 或VARCHAR 列,從而避免由于結尾空格的刪除而改變一些數據值的潛在問題。
- AES_ENCRYPT(*str*,*key_str*) , AES_DECRYPT(*crypt_str*,*key_str*)
這些函數允許使用官方AES進行加密和數據加密 (高級加密標準 ) 算法, 即以前人們所熟知的 “Rijndael”。保密關鍵字的長度為128比特,不過你可以通過改變源而將其延長到 256 比特。我們選擇了 128比特的原因是它的速度要快得多,且對于大多數用途而言這個保密程度已經夠用。??
輸入參數可以為任何長度。若任何一個參數為NULL,則函數的結果也是NULL。
因為 AES 是塊級算法,使用填充將不均衡長度字符串編碼,這樣結果字符串的長度的算法為 16 * (trunc(*string_length* / 16) + 1)。
若 AES_DECRYPT()檢測到無效數據或不正確填充,它會返回 NULL。然而,若輸入的資料或密碼無效時, AES_DECRYPT()有可能返回一個非 NULL 值 (可能為無用信息 )。
你可以通過修改你的問詢,從而使用AES函數以加密形式來存儲數據:
INSERT INTO t VALUES (1,AES_ENCRYPT('text','password'));
AES_ENCRYPT()和AES_DECRYPT() 可以被看作MySQL中普遍通用的密碼最安全的加密函數。
- DECODE(*crypt_str*,*pass_str*)
使用 *pass_str* 作為密碼,解密加密字符串 *crypt_str*, *crypt_str*應該是由ENCODE()返回的字符串。
- ENCODE(*str*,*pass_str*)
使用*pass_str*作為密碼,解密 *str*。 使用DECODE()解密結果。
結果是一個和*str*長度相同的二進制字符串。若你想要將其保留在一個列中,可使用 BLOB 列類型。
- DES_DECRYPT(*crypt_str*[,*key_str*])
使用DES_ENCRYPT()加密一個字符串。若出現錯誤,這個函數會返回 NULL。
注意,這個函數只有當MySQL在SSL 的支持下配置完畢時才會運作。請參見[5.8.7節,“使用安全連接”](# "5.8.7.?Using Secure Connections").
假如沒有給定 *key_str* 參數,? DES_DECRYPT() 會首先檢查加密字符串的第一個字節, 從而確定用來加密原始字符串的DES密碼關鍵字數字,之后從DES關鍵字文件中讀取關鍵字從而解密信息。為使其運行,用戶必須享有 SUPER 特權。可以選擇--des-key-file服務器指定關鍵字文件。
假如你向這個函數傳遞一個*key_str*參數,該字符串被用作解密信息的關鍵字。
若 *crypt_str* 參數看起來不是一個加密字符串, MySQL 會返回給定的 *crypt_str*。
- DES_ENCRYPT(*str*[,(*key_num*|*key_str*)])
用Triple-DES 算法給出的關鍵字加密字符串。若出現錯誤,這個函數會返回NULL。
注意,這個函數只有當MySQL 在SSL的支持下配置完畢后才會運行。請參見[5.8.7節,“使用安全連接”](# "5.8.7.?Using Secure Connections").
使用的加密關鍵字的選擇基于第二個到 DES_ENCRYPT()的參數,假如給定:?
<table border="1" cellpadding="0" id="table9"><tr><td> <p> <b> <span> 參數</span></b></p></td> <td> <p> <b> <span> 說明</span></b></p></td> </tr><tr><td> <p> <span> 無參數</span></p></td> <td> <p> <span> 使用來自<span>DES</span>關鍵字文件的第一個關鍵字。</span></p></td> </tr><tr><td> <p> <i> <span> key_num</span></i></p></td> <td> <p> <span> 使用<span>DES </span>關鍵字文件給出的關鍵字數字<span>(0-9)</span>。 </span></p></td> </tr><tr><td> <p> <i> <span> key_str</span></i></p></td> <td> <p> <span> 使用給出的關鍵字字符串為 <i><span>str</span></i><span> </span>加密。</span></p></td> </tr></table>
選擇--des-key-file服務器指定關鍵字文件。
返回字符串是一個二進制字符串,其中第一個字符為 CHAR(128 | key_num)。
加上 128使得識別加密關鍵字更加容易。若你使用一個字符串關鍵字,則 *key_num*為127。
結果的字符串長度為? *new_len* = *orig_len* + (8-(*orig_len* % 8))+1。
DES關鍵字文件中的每一行都具有如下格式:
* key_num**des_key_str*
每個*key_num*必須是一個從0到0范圍內的數字。文件中行的排列順序是任意的。 *des_key_str* 是用來加密信息的字符串。在數字和關鍵字之間應該至少有一個空格。若你未指定任何到DES_ENCRYPT()的關鍵字參數,則第一個關鍵字為默認的使用關鍵字。
使用FLUSH DES_KEY_FILE語句,你可以讓 MySQL從關鍵字文件讀取新的關鍵字值。這要求你享有 RELOAD特權。
擁有一套默認關鍵字的一個好處就是它向應用程序提供了一個檢驗加密列值的方式,而無須向最終用戶提供解密這些值的權力。
mysql> **SELECT customer_address FROM customer_table **
???? > WHERE crypted_credit_card = DES_ENCRYPT('credit_card_number');
- ENCRYPT(*str*[,*salt*])
使用Unix crypt() 系統調用加密 *str*。 *salt*參數應為一個至少包含2個字符的字符串。若沒有給出 *salt*參數,則使用任意值。
mysql> **SELECT ENCRYPT('hello');**
??????? -> 'VxuFAJXVARROc'
至少在一些系統中,ENCRYPT()除了s*tr*的前八位字符之外會忽略所有內容。這個行為由下劃線的crypt() 系統調用的執行所決定。
假如crypt()在你的系統中不可用(正如在 Windows系統), ENCRYPT() 則會始終返回NULL。鑒于這個原因,我們向你推薦使用 MD5() 或SHA1() 來代替,因為這兩個函數適合所有的平臺。
- MD5(*str*)
為字符串算出一個 MD5 128比特檢查和。該值以32位十六進制數字的二進制字符串的形式返回, 若參數為 NULL 則會返回 NULL。例如,返回值可被用作散列關鍵字。
mysql> **SELECT MD5('testing');**
??????? -> 'ae2b1fca515949e5d54fb22b8ed95575'
這是"RSA Data Security, Inc. MD5 Message-Digest Algorithm."
假如你想要將這個值轉化為大寫字母,參見[12.8節,“Cast函數和操作符”](# "12.8.?Cast Functions and Operators")中BINARY操作符項中給出的二進制字符串轉換。
- OLD_PASSWORD(*str*)
當PASSWORD()的執行變為改善安全性時,OLD_PASSWORD()會被添加到 MySQL。OLD_PASSWORD()返回從前的PASSWORD()執行值( 4.1之前),同時允許你為任何4.1 之前的需要連接到你的5.1 版本MySQL服務器前客戶端設置密碼,從而不至于將它們切斷。請參見[5.7.9節,“MySQL 4.1中的密碼哈希處理”](# "5.7.9.?Password Hashing in MySQL 4.1")。
- PASSWORD(*str*)
從原文密碼*str*計算并返回密碼字符串,當參數為 NULL 時返回 NULL。這個函數用于用戶授權表的Password列中的加密MySQL密碼存儲
mysql> **SELECT PASSWORD('badpwd');**
??????? -> '7f84554057dd964b'
PASSWORD() 加密是單向的 (不可逆 )。
PASSWORD() 執行密碼加密與Unix 密碼被加密的方式不同。請參見ENCRYPT()。
**注釋**: PASSWORD()函數在MySQL服務器中的鑒定系統使用;你*不*應將它用在你個人的應用程序中。為達到同樣目的,可使用 MD5()或SHA1() 代替。??? 更多關于在您的應用程序中處理密碼及安全鑒定的信息見RFC 2195?
- SHA1(*str*) SHA(*str*)
為字符串算出一個 SHA1 160比特檢查和,如RFC 3174 (安全散列算法 )中所述。該值被作為40位十六進制數字返回,而當參數為NULL 時則返回 NULL。這個函數的一個可能的用處就在于其作為散列關鍵字。你也可以將其作為存儲密碼的密碼安全函數使用。
mysql> **SELECT SHA1('abc');**
??????? -> 'a9993e364706816aba3e25717850c26c9cd0d89d'
SHA1()可以被視為一個密碼更加安全的函數,相當于? MD5()。 SHA() 和SHA1()具有相同的意義。
### 12.9.3.?信息函數
- BENCHMARK(*count*,*expr*)
BENCHMARK() 函數重復*count*次執行表達式 *expr*。 它可以被用于計算? MySQL 處理表達式的速度。結果值通常為 0。另一種用處來自 **mysql**客戶端內部,能夠報告問詢執行的次數:
~~~
mysql> SELECT BENCHMARK(1000000,ENCODE('hello','goodbye'));
~~~
~~~
+----------------------------------------------+
~~~
~~~
| BENCHMARK(1000000,ENCODE('hello','goodbye')) |
~~~
~~~
+----------------------------------------------+
~~~
~~~
|??????????????????????????????????????????? 0 |
~~~
~~~
+----------------------------------------------+
~~~
~~~
1 row in set (4.74 sec)
~~~
此處報告的時間是客戶端上的共用時間,而不是服務器端上的CPU時間。建議執行多遍BENCHMARK(),并解釋與服務器機器負荷程度有關的結果。
·???????? CHARSET(*str*)
返回字符串自變量的字符集。
~~~
mysql> SELECT CHARSET('abc');
~~~
~~~
??????? -> 'latin1'
~~~
~~~
mysql> SELECT CHARSET(CONVERT('abc' USING utf8));
~~~
~~~
??????? -> 'utf8'
~~~
~~~
mysql> SELECT CHARSET(USER());
~~~
~~~
??????? -> 'utf8'
~~~
·???????? COERCIBILITY(*str*)
返回字符串自變量的整序可壓縮性值。
~~~
mysql> SELECT COERCIBILITY('abc' COLLATE latin1_swedish_ci);
~~~
~~~
??????? -> 0
~~~
~~~
mysql> SELECT COERCIBILITY(USER());
~~~
~~~
??????? -> 3
~~~
~~~
mysql> SELECT COERCIBILITY('abc');
~~~
~~~
??????? -> 4
~~~
返回值具有如下意義:****
<table border="1" cellpadding="0" id="table10"><tr><td> <p><strong> <span>可壓縮性 </span> </strong></p></td> <td> <p><strong> <span>意義</span></strong></p></td> <td> <p><strong> <span>舉例</span></strong></p></td> </tr><tr><td> <p> <span>0</span></p></td> <td> <p> <span>明確排序</span></p></td> <td> <p> <span>帶有</span><span>COLLATE</span><span> </span><span>子句的值</span></p></td> </tr><tr><td> <p> <span>1</span></p></td> <td> <p> <span>無排序</span></p></td> <td> <p> <span>不同排序的字符串連接 </span></p></td> </tr><tr><td> <p> <span>2</span></p></td> <td> <p> <span>明確排序</span></p></td> <td> <p> <span>列值</span></p></td> </tr><tr><td> <p> <span>3</span></p></td> <td> <p> <span>系統常量</span></p></td> <td> <p> <span>USER()</span><span>返回值</span></p></td> </tr><tr><td> <p> <span>4</span></p></td> <td> <p> <span>可壓縮</span></p></td> <td> <p> <span>文字字符串</span></p></td> </tr><tr><td> <p> <span>5</span></p></td> <td> <p> <span>可忽略</span></p></td> <td> <p><span> <span>NULL</span><span>得來的<span>NULL</span></span></span><span>或一個表達式 </span></p></td> </tr></table>
** ?**
?
下方值得優先級較高。
- COLLATION(*str*)
返回惠字符串參數的排序方式。
mysql> **SELECT COLLATION('abc');**
??????? -> 'latin1_swedish_ci'
mysql> **SELECT COLLATION(_utf8'abc');**
??????? -> 'utf8_general_ci'
- CONNECTION_ID()
返回對于連接的連接ID (線程ID)。每個連接都有各自的唯一 ID。
mysql> **SELECT CONNECTION_ID();**
??????? -> 23786
- CURRENT_USER, CURRENT_USER()
返回當前話路被驗證的用戶名和主機名組合。這個值符合確定你的存取權限的MySQL 賬戶。在被指定SQL SECURITY DEFINER特征的存儲程序內, CURRENT_USER() 返回程序的創建者。
?CURRENT_USER()的值可以和USER()的值有所不同。
mysql> **SELECT USER();**
??????? -> 'davida@localhost'
mysql> **SELECT * FROM mysql.user;**
ERROR 1044: Access denied for user ''@'localhost' to
database 'mysql'
mysql> **SELECT CURRENT_USER();**
??????? -> '@localhost'
這個例子解釋了雖然客戶端指定了一個 davida用戶名 (正如USER()函數的值所指示的), 服務器卻使用一個匿名的用戶賬戶確認該客戶端 (見CURRENT_USER()值得空用戶名部分 )。這種情況發生的一個原因是 One 在向 davida的授權列表中沒有足夠的賬戶。?
?CURRENT_USER() 返回的字符串使用 utf8字符集。
- DATABASE()
返回使用 utf8 字符集的默認(當前)數據庫名。在存儲程序里,默認數據庫是同該程序向關聯的數據庫,但并不一定與調用語境的默認數據庫相同。?
mysql> **SELECT DATABASE();**
??????? -> 'test'
若沒有默認數據庫, DATABASE()返回 NULL。
- FOUND_ROWS()
A SELECT語句可能包括一個 LIMIT 子句,用來限制服務器返回客戶端的行數。在有些情況下,需要不用再次運行該語句而得知在沒有LIMIT 時到底該語句返回了多少行。為了知道這個行數, 包括在SELECT 語句中選擇? SQL_CALC_FOUND_ROWS ,隨后調用 FOUND_ROWS() :
mysql> **SELECT SQL_CALC_FOUND_ROWS * FROM *tbl_name***
? ??-> **WHERE id > 100 LIMIT 10;**
mysql> **SELECT FOUND_ROWS();**
第二個 SELECT返回一個數字,指示了在沒有LIMIT子句的情況下,第一個SELECT返回了多少行 (若上述的 SELECT語句不包括 SQL_CALC_FOUND_ROWS 選項,則使用LIMIT 和不使用時,FOUND_ROWS() 可能會返回不同的結果)。
通過 FOUND_ROWS()的有效行數是瞬時的,并且不用于越過SELECT SQL_CALC_FOUND_ROWS語句后面的語句。若你需要稍候參閱這個值,那么將其保存:
mysql> **SELECT SQL_CALC_FOUND_ROWS * FROM ... ;**
mysql> **SET @rows = FOUND_ROWS();**
假如你正在使用 SELECT SQL_CALC_FOUND_ROWS, MySQL 必須計算出在全部結果集合中有所少行。然而, 這比不用LIMIT而再次運行問詢要快,原因是結果集合不需要被送至客戶端。
SQL_CALC_FOUND_ROWS 和 FOUND_ROWS() 在當你希望限制一個問詢返回的行數時很有用,同時還能不需要再次運行問詢而確定全部結果集合中的行數。一個例子就是提供頁式顯示的Web腳本,該顯示包含顯示搜索結果其它部分的頁的連接。使用FOUND_ROWS() 使你確定剩下的結果需要多少其它的頁。?
SQL_CALC_FOUND_ROWS 和 FOUND_ROWS() 的應用對于UNION 問詢比對于簡單SELECT 語句更為復雜,原因是在UNION 中,LIMIT 可能會出現在多個位置。它可能適用于UNION中的個人 SELECT語句,或是總體上? 到UNION 結果的全程。
SQL_CALC_FOUND_ROWS對于 UNION的意向是它應該不需要全程LIMIT而返回應返回的行數。SQL_CALC_FOUND_ROWS 和UNION 一同使用的條件是:
- ?SQL_CALC_FOUND_ROWS 關鍵詞必須出現在UNION的第一個 SELECT中。
- ?FOUND_ROWS()的值只有在使用 UNION ALL時才是精確的。若使用不帶ALL的UNION,則會發生兩次刪除, 而? FOUND_ROWS() 的指只需近似的。
- 假若UNION 中沒有出現? LIMIT ,則SQL_CALC_FOUND_ROWS 被忽略,返回臨時表中的創建的用來處理UNION的行數。
- LAST_INSERT_ID() LAST_INSERT_ID(*expr*)
自動返回*最后一個*INSERT或 UPDATE 問詢為 AUTO_INCREMENT列設置的*第一個 *發生的值。
mysql> **SELECT LAST_INSERT_ID();**
??????? -> 195
產生的ID *每次連接后*保存在服務器中。這意味著函數向一個給定客戶端返回的值是該客戶端產生對影響AUTO_INCREMENT列的最新語句第一個 AUTO_INCREMENT值的。這個值不能被其它客戶端影響,即使它們產生它們自己的 AUTO_INCREMENT值。這個行為保證了你能夠找回自己的 ID 而不用擔心其它客戶端的活動,而且不需要加鎖或處理。
假如你使用一個非“magic”值來更新某一行的AUTO_INCREMENT 列,則LAST_INSERT_ID() 的值不會變化(換言之, 一個不是 NULL也不是 0的值)。
**重點**: 假如你使用單INSERT語句插入多個行,? LAST_INSERT_ID() *只*返回插入的*第一*行產生的值。其原因是這使依靠其它服務器復制同樣的 INSERT語句變得簡單。
例如:
~~~
mysql> USE test;
~~~
~~~
Database changed
~~~
~~~
mysql> CREATE TABLE t (
~~~
~~~
??? ->?? id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
~~~
~~~
??? ->?? name VARCHAR(10) NOT NULL
~~~
~~~
??? -> );
~~~
~~~
Query OK, 0 rows affected (0.09 sec)
~~~
~~~
?
~~~
~~~
mysql> INSERT INTO t VALUES (NULL, 'Bob');
~~~
~~~
Query OK, 1 row affected (0.01 sec)
~~~
~~~
?
~~~
~~~
mysql> SELECT * FROM t;
~~~
~~~
+----+------+
~~~
~~~
| id | name |
~~~
~~~
+----+------+
~~~
~~~
|? 1 | Bob? |
~~~
~~~
+----+------+
~~~
~~~
1 row in set (0.01 sec)
~~~
~~~
?
~~~
~~~
mysql> SELECT LAST_INSERT_ID();
~~~
~~~
+------------------+
~~~
~~~
| LAST_INSERT_ID() |
~~~
~~~
+------------------+
~~~
~~~
|??????????????? 1 |
~~~
~~~
+------------------+
~~~
~~~
1 row in set (0.00 sec)
~~~
~~~
?
~~~
~~~
mysql> INSERT INTO t VALUES
~~~
~~~
??? -> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
~~~
~~~
Query OK, 3 rows affected (0.00 sec)
~~~
~~~
Records: 3? Duplicates: 0? Warnings: 0
~~~
~~~
?
~~~
~~~
mysql> SELECT * FROM t;
~~~
~~~
+----+------+
~~~
~~~
| id | name |
~~~
~~~
+----+------+
~~~
~~~
|? 1 | Bob? |
~~~
~~~
|? 2 | Mary |
~~~
~~~
|? 3 | Jane |
~~~
~~~
|? 4 | Lisa |
~~~
~~~
+----+------+
~~~
~~~
4 rows in set (0.01 sec)
~~~
~~~
?
~~~
~~~
mysql> SELECT LAST_INSERT_ID();
~~~
~~~
+------------------+
~~~
~~~
| LAST_INSERT_ID() |
~~~
~~~
+------------------+
~~~
~~~
|??????????????? 2 |
~~~
~~~
+------------------+
~~~
~~~
1 row in set (0.00 sec)
~~~
雖然第二個問詢將3 個新行插入 t, 對這些行的第一行產生的 ID 為 2, 這也是 LAST_INSERT_ID()返回的值。
假如你使用 INSERT IGNORE而記錄被忽略,則AUTO_INCREMENT 計數器不會增量,而 LAST_INSERT_ID() 返回0, 這反映出沒有插入任何記錄。
若給出作為到LAST_INSERT_ID()的參數*expr*,則參數的值被函數返回,并作為被LAST_INSERT_ID()返回的下一個值而被記憶。這可用于模擬序列:
- 創建一個表,用來控制順序計數器并使其初始化:
o???????????????????? mysql> **CREATE TABLE sequence (id INT NOT NULL);**
o???????????????????? mysql> **INSERT INTO sequence VALUES (0);**
- 使用該表產生這樣的序列數 :
o???????????????????? mysql> **UPDATE sequence SET id=LAST_INSERT_ID(id+1);**
o???????????????????? mysql> **SELECT LAST_INSERT_ID();**
UPDATE 語句會增加順序計數器并引發向LAST_INSERT_ID()? 的下一次調用,用來返回升級后的值。 SELECT 語句會檢索這個值。? mysql_insert_id() C API函數也可用于獲取這個值。 見[25.2.3.36節,“mysql_insert_id()”](# "25.2.3.36.?mysql_insert_id()").
你可以不用調用LAST_INSERT_ID()而產生序列,但這樣使用這個函數的效用在于 ID值被保存在服務器中,作為自動產生的值。它適用于多個用戶,原因是多個用戶均可使用 UPDATE語句并用SELECT語句(或mysql_insert_id()),得到他們自己的序列值,而不會影響其它產生他們自己的序列值的客戶端或被其它產生他們自己的序列值的客戶端所影響。
注意, mysql_insert_id() 僅會在INSERT 和UPDATE語句后面被升級, 因此你不能在執行了其它諸如SELECT或 SET 這樣的SQL語句后使用 C API 函數來找回 LAST_INSERT_ID(*expr*) 對應的值。
- ROW_COUNT()
ROW_COUNT()返回被前面語句升級的、插入的或刪除的行數。 這個行數和 **mysql** 客戶端顯示的行數及 mysql_affected_rows() C API 函數返回的值相同。
mysql> **INSERT INTO t VALUES(1),(2),(3);**
問詢完成, 表中有3 行 (0.00秒)
記錄: 3 重復: 0 警告: 0
?
mysql> **SELECT ROW_COUNT();**
+-------------+
| ROW_COUNT() |
+-------------+
|?????????? 3 |
+-------------+
表中有1行 (0.00 秒)
?
mysql> **DELETE FROM t WHERE i IN(1,2);**
問詢完成, 找到2 行 (0.00 秒)
?
mysql> **SELECT ROW_COUNT();**
+-------------+
| ROW_COUNT() |
+-------------+
|?????????? 2 |
+-------------+
表中有1行 (0.00 秒)
- SCHEMA()
這個函數和 DATABASE()具有相同的意義。
- SESSION_USER()
SESSION_USER()和 USER()具有相同的意義。
- SYSTEM_USER()
SYSTEM_USER()合 USER()具有相同的意義。
- USER()
返回當前 MySQL用戶名和機主名/
mysql> **SELECT USER();**
??????? -> 'davida@localhost'
這個值指示了你指定的連接服務器時的用戶名,及你所連接的客戶主機。這個值可以和CURRENT_USER() 的值不同。
你可以這樣提取用戶名部分:
mysql> **SELECT SUBSTRING_INDEX(USER(),'@',1);**
??????? -> 'davida'
由于 USER() 返回一個utf8 字符集中的值,你也應確保'@' 字符串文字在該字符集中得到解釋:
mysql> **SELECT SUBSTRING_INDEX(USER(),_utf8'@',1);**
??????? -> 'davida'
- VERSION()
返回指示 MySQL 服務器版本的字符串。這個字符串使用 utf8 字符集。
mysql> **SELECT VERSION();**
??????? -> '5.1.2-alpha-standard'
注意,假如你的版本字符串以-log結尾,這說明登錄已被激活。?
### 12.9.4.?其他函數
- DEFAULT(*col_name*)
返回一個表列的默認值。若該列沒有默認值則會產生錯誤。
mysql> **UPDATE t SET i = DEFAULT(i)+1 WHERE id < 100;**
- FORMAT(*X*,*D*)
將數字*X*的格式寫為'#,###,###.##',以四舍五入的方式保留小數點后 *D*位, 并將結果以字符串的形式返回。若? *D*為 0, 則返回結果不帶有小數點,或不含小數部分。
mysql> **SELECT FORMAT(12332.123456, 4);**
??????? -> '12,332.1235'
mysql> **SELECT FORMAT(12332.1,4);**
??????? -> '12,332.1000'
mysql> **SELECT FORMAT(12332.2,0);**
??????? -> '12,332'
- GET_LOCK(*str*,*timeout*)
設法使用字符串*str* 給定的名字得到一個鎖, 超時為*timeout*秒。若成功得到鎖,則返回 1,若操作超時則返回0? (例如,由于另一個客戶端已提前封鎖了這個名字 ),若發生錯誤則返回NULL (諸如缺乏記憶或線程**mysqladmin kill**被斷開 )。假如你有一個用GET_LOCK()得到的鎖,當你執行RELEASE_LOCK()或你的連接斷開(正常或非正常)時,這個鎖就會解除。
這個函數可用于執行應用程序鎖或模擬記錄鎖定。名稱被鎖定在服務器范圍內。假如一個名字已經被一個客戶端封鎖, GET_LOCK() 會封鎖來自另一個客戶端申請封鎖同一個名字的任何請求。這使對一個封鎖名達成協議的客戶端使用這個名字合作執行建議鎖。然而要知道它也允許不在一組合作客戶端中的一個客戶端封鎖名字,不論是服役的還是非故意的,這樣阻止任何合作中的客戶端封鎖這個名字。一個減少這種情況發生的辦法就是使用數據庫特定的或應用程序特定的封鎖名。例如,? 使用*db_name.str*或 *app_name.str* 形式的封鎖名。
mysql> **SELECT GET_LOCK('lock1',10);**
??????? -> 1
mysql> **SELECT IS_FREE_LOCK('lock2');**
??????? -> 1
mysql> **SELECT GET_LOCK('lock2',10);**
??????? -> 1
mysql> **SELECT RELEASE_LOCK('lock2');**
??????? -> 1
mysql> **SELECT RELEASE_LOCK('lock1');**
??????? -> NULL
注意,第二個 RELEASE_LOCK()調用返回 NULL ,原因是鎖'lock1' 杯第二個GET_LOCK()調用解開。
- INET_ATON(*expr*)
給出一個作為字符串的網絡地址的點地址表示,返回一個代表該地址數值的整數。地址可以是4或8比特地址。
mysql> **SELECT INET_ATON('209.207.224.40');**
??????? -> 3520061480
產生的數字總是按照網絡字節順序。如上面的例子,數字按照 209×2563 + 207×2562 + 224×256 + 40 進行計算。
INET_ATON() 也能理解短格式 IP 地址:
mysql> **SELECT INET_ATON('127.0.0.1'), INET_ATON('127.1');**
??????? -> 2130706433, 2130706433
**注釋**: 在存儲由INET_ATON() 產生的值時,推薦你使用 INT UNSIGNED 列。假如你使用 (帶符號) INT列, 則相應的第一個八位組大于127的IP 地址值會被截至? 2147483647 (即, INET_ATON('127.255.255.255') 所返回的值)。請參見[11.2節,“數值類型”](# "11.2.?Numeric Types")。
- INET_NTOA(*expr*)
給定一個數字網絡地址 (4 或 8 比特),返回作為字符串的該地址的電地址表示。
mysql> **SELECT INET_NTOA(3520061480);**
??????? -> '209.207.224.40'
- IS_FREE_LOCK(*str*)
檢查名為*str*的鎖是否可以使用 (換言之,沒有被封鎖)。若鎖可以使用,則返回? 1? (沒有人在用這個鎖), 若這個鎖正在被使用,則返回0 ,出現錯誤則返回 NULL? (諸如不正確的參數 )。
- IS_USED_LOCK(*str*)
檢查名為*str*的鎖是否正在被使用(換言之,被封鎖)。若被封鎖,則返回使用該鎖的客戶端的連接標識符。否則返回 NULL。
- MASTER_POS_WAIT(*log_name*,*log_pos*[,*timeout*])
該函數對于控制主從同步很有用處。它會持續封鎖,直到從設備閱讀和應用主機記錄中所有補充資料到指定的位置。返回值是其為到達指定位置而必須等待的記錄事件的數目。若從設備SQL線程沒有被啟動、從設備主機信息尚未初始化、參數不正確或出現任何錯誤,則該函數返回 NULL。若超時時間被超過,則返回-1。若在MASTER_POS_WAIT() 等待期間,從設備SQL線程中止,則該函數返回 NULL。若從設備由指定位置通過,則函數會立即返回結果。
假如已經指定了一個*超時時間*值,當 *超時時間*秒數經過后MASTER_POS_WAIT()會停止等待。*超時時間* 必須大于 0;一個為零或為負值的 *超時時間* 表示沒有超市時間。?
- NAME_CONST(*name*,*value*)
返回給定值。 當用來產生一個結果集合列時, NAME_CONST()促使該列使用給定名稱。?
mysql> **SELECT NAME_CONST('myname', 14);**
+--------+
| myname |
+--------+
|???? 14 |
+--------+
這個函數被添加進 MySQL 5.0.12。它只做內部使用。 服務器在書寫來自包含局部程序變量的存儲程序的語句時會用到它,詳見[20.4節,“存儲子程序和觸發程序的二進制日志功能”](# "20.4.?Binary Logging of Stored Routines and Triggers")。你可能會在**mysqlbinlog**的書櫥中看到這個函數。
- RELEASE_LOCK(*str*)
解開被GET_LOCK()獲取的,用字符串*str*所命名的鎖。若鎖被解開,則返回? 1,若改線程尚未創建鎖,則返回0 (此時鎖沒有被解開 ), 若命名的鎖不存在,則返回 NULL。若該鎖從未被對GET_LOCK()的調用獲取,或鎖已經被提前解開,則該鎖不存在。
DO 語句和RELEASE_LOCK()同時使用很方便。請參見[13.2.2節,“DO語法”](# "13.2.2.?DO Syntax")。
- SLEEP(*duration*)
睡眠(暫停) 時間為*duration*參數給定的秒數,然后返回 0。若 SLEEP() 被中斷,它會返回 1。 duration 或許或包括一個給定的以微秒為單位的分數部分。
- UUID()
返回一個通用唯一標識符(UUID) ,其產生的根據是《DCE 1.1: 遠程過程調用》 (附錄A) CAE (公共應用軟件環境) 的說明,該作品于1997年10月由 The Open Group 出版 (文件編號 C706, [ http://www.opengroup.org/public/pubs/catalog/c706.htm](http://www.opengroup.org/public/pubs/catalog/c706.htm)).
UUID被設計成一個在時間和空間上都獨一無二的數字。2個對UUID() 的調用應產生2個不同的值,即使這些調用的執行是在兩個互不相連的單獨電腦上進行。
UUID 是一個由5位十六進制數的字符串表示的128比特數字 ,其格式為? aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee :
- 前3個數字從一個時間戳產生。?
- 第4 個數字保持暫時唯一性,以防時間戳值失去單一性 (例如, 由于經濟時)。
- 第5個數字是一個 IEEE 802 節點號,它提供空間唯一性。若后者不可用,則用一個隨機數字替換。 (例如, 由于主機沒有以太網卡,或我們不知道怎樣在你的操作系統上找到界面的機器地址 )。假若這樣,空間唯一性就不能得到保證。盡管如此,一個沖突的發生機率還是*非常*低的。
目前,一個界面的 MAC 地址盡被FreeBSD 和 Linux考慮到。在其它操作系統中, MySQL使用隨機產生的 48比特數字。
mysql> **SELECT UUID();**
??????? -> '6ccd780c-baba-1026-9564-0040f4311e29'
注意, UUID() 不支持復制功能。
- VALUES(*col_name*)
在一個INSERT … ON DUPLICATE KEY UPDATE …語句中,你可以在UPDATE 子句中使用 VALUES(*col_name*)函數,用來訪問來自該語句的INSERT 部分的列值。換言之,UPDATE 子句中的 VALUES(*col_name*) 訪問需要被插入的*col_name *的值,并不會發生重復鍵沖突。這個函數在多行插入中特別有用。? VALUES()函數只在INSERT ... UPDATE 語句中有意義,而在其它情況下只會返回 NULL。請參見[13.2.4節,“INSERT語法”](# "13.2.4.?INSERT Syntax").
mysql> **INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)**
??? -> **ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);**
### 12.10.?與GROUP BY子句同時使用的函數和修改程序``
[12.10.1. GROUP BY(聚合)函數](#)[12.10.2. GROUP BY修改程序](#)[12.10.3. 具有隱含字段的GROUP BY](#)
### 12.10.1.?GROUP BY(聚合)函數
本章論述了用于一組數值操作的 group (集合)函數。除非另作說明, group 函數會忽略 NULL 值。
假如你在一個不包含 ROUP BY子句的語句中使用一個 group函數 ,它相當于對所有行進行分組。
- AVG([DISTINCT] *expr*)
返回*expr*的平均值。 DISTINCT 選項可用于返回 *expr*的不同值的平均值。
若找不到匹配的行,則AVG()返回 NULL 。
mysql> **SELECT student_name, AVG(test_score)**
??? ->??????? **FROM student**
??? ->??????? **GROUP BY student_name;**
- BIT_AND(*expr*)
返回*expr*中所有比特的 bitwise AND 。計算執行的精確度為64比特(BIGINT) 。
若找不到匹配的行,則這個函數返回 18446744073709551615 。(這是無符號 BIGINT 值,所有比特被設置為 1)。
- BIT_OR(*expr*)
返回*expr*中所有比特的bitwise OR。計算執行的精確度為64比特(BIGINT) 。
若找不到匹配的行,則函數返回 0 。
- BIT_XOR(*expr*)
返回*expr*中所有比特的bitwise XOR。計算執行的精確度為64比特(BIGINT) 。
若找不到匹配的行,則函數返回 0 。
- COUNT(*expr*)
返回SELECT語句檢索到的行中非NULL值的數目。??
若找不到匹配的行,則COUNT() 返回 0 。
mysql> **SELECT student.student_name,COUNT(*)**
??? ->??????? **FROM student,course**
??? ->??????? **WHERE student.student_id=course.student_id**
??? ->??????? **GROUP BY student_name;**
?
COUNT(*) 的稍微不同之處在于,它返回檢索行的數目, 不論其是否包含 NULL值。
SELECT 從一個表中檢索,而不檢索其它的列,并且沒有 WHERE子句時, COUNT(*)被優化到最快的返回速度。例如:
mysql> **SELECT COUNT(*) FROM student;**
這個優化僅適用于 MyISAM表, 原因是這些表類型會儲存一個函數返回記錄的精確數量,而且非常容易訪問。對于事務型的存儲引擎(InnoDB, BDB), 存儲一個精確行數的問題比較多,原因是可能會發生多重事物處理, 而每個都可能會對行數產生影響。
- COUNT(DISTINCT *expr*,[*expr*...])
返回不同的非NULL值數目。
若找不到匹配的項,則COUNT(DISTINCT)返回 0 。
mysql> **SELECT COUNT(DISTINCT results) FROM student;**
在MySQL中, 你通過給定一個表達式列表而獲取不包含NULL 不同表達式組合的數目。在標準 SQL中,你將必須在COUNT(DISTINCT ...)中連接所有表達式。
- GROUP_CONCAT(*expr*)
該函數返回帶有來自一個組的連接的非NULL值的字符串結果。其完整的語法如下所示:?
GROUP_CONCAT([DISTINCT] *expr* [,*expr* ...]
???????????? [ORDER BY {*unsigned_integer* | *col_name* | *expr*}
???????????????? [ASC | DESC] [,*col_name* ...]]
???????????? [SEPARATOR *str_val*])
mysql> **SELECT student_name,**
??? ->???? **GROUP_CONCAT(test_score)**
??? ->???? **FROM student**
??? ->???? **GROUP BY student_name;**
Or:
mysql> **SELECT student_name,**
??? ->???? **GROUP_CONCAT(DISTINCT test_score**
??? ->?????????????? **ORDER BY test_score DESC SEPARATOR ' ')**
??? ->???? **FROM student**
??? ->???? **GROUP BY student_name;**
在MySQL中,你可以獲取表達式組合的連接值。你可以使用DISTINCT刪去重復值。假若你希望多結果值進行排序,則應該使用? ORDER BY子句。若要按相反順序排列,將 DESC (遞減) 關鍵詞添加到你要用ORDER BY 子句進行排序的列名稱中。默認順序為升序;可使用ASC將其明確指定。?? SEPARATOR 后面跟隨應該被插入結果的值中間的字符串值。默認為逗號 (‘,’)。通過指定SEPARATOR '' ,你可以刪除所有分隔符。
使用group_concat_max_len系統變量,你可以設置允許的最大長度。? 程序中進行這項操作的語法如下,其中 val 是一個無符號整數:
SET [SESSION | GLOBAL] group_concat_max_len = val;
若已經設置了最大長度, 則結果被截至這個最大長度。
- MIN([DISTINCT] *expr*), MAX([DISTINCT] *expr*)
返回*expr* 的最小值和最大值。 MIN() 和 MAX() 的取值可以是一個字符串參數;在這些情況下, 它們返回最小或最大字符串值。請參見[7.4.5節,“MySQL如何使用索引”](# "7.4.5.?How MySQL Uses Indexes")。? DISTINCT關鍵詞可以被用來查找*expr*的不同值的最小或最大值,然而,這產生的結果與省略DISTINCT 的結果相同。
若找不到匹配的行,MIN()和MAX()返回 NULL 。
mysql> **SELECT student_name, MIN(test_score), MAX(test_score)**
??? ->??????? **FROM student**
??? ->??????? **GROUP BY student_name;**
對于MIN()、 MAX()和其它集合函數, MySQL當前按照它們的字符串值而非字符串在集合中的相關位置比較 ENUM和 SET 列。這同ORDER BY比較二者的方式有所不同。這一點應該在MySQL的未來版本中得到改善。?
- STD(*expr*) STDDEV(*expr*)
返回*expr*的總體標準偏差。這是標準 SQL 的延伸。這個函數的STDDEV() 形式用來提供和Oracle 的兼容性。可使用標準SQL函數 STDDEV_POP() 進行代替。
若找不到匹配的行,則這些函數返回 NULL 。
- STDDEV_POP(*expr*)
返回*expr*的總體標準偏差(VAR_POP()的平方根)。你也可以使用? STD() 或STDDEV(), 它們具有相同的意義,然而不是標準的 SQL。
若找不到匹配的行,則STDDEV_POP()返回 NULL。
- STDDEV_SAMP(*expr*)
返回*expr*的樣本標準差 ( VAR_SAMP()的平方根)。
若找不到匹配的行,則STDDEV_SAMP() 返回 NULL 。
- SUM([DISTINCT] *expr*)
返回*expr*的總數。 若返回集合中無任何行,則 SUM() 返回NULL。DISTINCT 關鍵詞可用于 MySQL 5.1 中,求得*expr *不同值的總和。
若找不到匹配的行,則SUM()返回 NULL。
- VAR_POP(*expr*)
返回*expr*總體標準方差。它將行視為總體,而不是一個樣本, 所以它將行數作為分母。你也可以使用 VARIANCE(),它具有相同的意義然而不是 標準的 SQL。
若找不到匹配的項,則VAR_POP()返回NULL。
- VAR_SAMP(*expr*)
返回*expr*的樣本方差。更確切的說,分母的數字是行數減去1。??
若找不到匹配的行,則VAR_SAMP()返回NULL。
- VARIANCE(*expr*)
返回*expr*的總體標準方差。這是標準SQL 的延伸。可使用標準SQL 函數 VAR_POP() 進行代替。
若找不到匹配的項,則VARIANCE()返回NULL。
### 12.10.2.?GROUP BY修改程序
GROUP BY子句允許一個將額外行添加到簡略輸出端 WITH ROLLUP 修飾符。這些行代表高層(或高聚集)簡略操作。ROLLUP 因而允許你在多層分析的角度回答有關問詢的問題。例如,它可以用來向OLAP (聯機分析處理) 操作提供支持。
設想一個名為sales 的表具有年份、國家、產品及記錄銷售利潤的利潤列:
CREATE TABLE sales
(
??? year??? INT NOT NULL,
??? country VARCHAR(20) NOT NULL,
??? product VARCHAR(32) NOT NULL,
??? profit? INT
);
可以使用這樣的簡單GROUP BY,每年對表的內容做一次總結:
mysql> **SELECT year, SUM(profit) FROM sales GROUP BY year;**
+------+-------------+
| year | SUM(profit) |
+------+-------------+
| 2000 |??????? 4525 |
| 2001 |??????? 3010 |
+------+-------------+
這個輸出結果顯示了每年的總利潤, 但如果你也想確定所有年份的總利潤,你必須自己累加每年的單個值或運行一個加法詢問。
或者你可以使用 ROLLUP, 它能用一個問詢提供雙層分析。將一個 WITH ROLLUP修飾符添加到GROUP BY 語句,使詢問產生另一行結果,該行顯示了所有年份的總價值:
mysql> **SELECT year, SUM(profit) FROM sales GROUP BY year WITH ROLLUP;**
+------+-------------+
| year | SUM(profit) |
+------+-------------+
| 2000 |??????? 4525 |
| 2001 |??????? 3010 |
| NULL |??????? 7535 |
+------+-------------+
總計高聚集行被年份列中的NULL值標出。
當有多重 GROUP BY 列時,ROLLUP產生的效果更加復雜。這時,每次在除了最后一個分類列之外的任何列出現一個 “break” (值的改變) ,則問訊會產生一個高聚集累計行。
例如,在沒有 ROLLUP的情況下,一個以年、國家和產品為基礎的關于 sales 表的一覽表可能如下所示:
mysql> **SELECT year, country, product, SUM(profit)**
??? -> **FROM sales**
??? -> **GROUP BY year, country, product;**
+------+---------+------------+-------------+
| year | country | product??? | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer?? |??????? 1500 |
| 2000 | Finland | Phone????? |???????? 100 |
| 2000 | India?? | Calculator |???????? 150 |
| 2000 | India?? | Computer?? |??????? 1200 |
| 2000 | USA???? | Calculator |????????? 75 |
| 2000 | USA???? | Computer?? |?? ?????1500 |
| 2001 | Finland | Phone????? |????????? 10 |
| 2001 | USA???? | Calculator |????????? 50 |
| 2001 | USA???? | Computer?? |??????? 2700 |
| 2001 | USA???? | TV???????? |???????? 250 |
+------+---------+------------+-------------+
表示總值的輸出結果僅位于年/國家/產品的分析級別。當添加了 ROLLUP后, 問詢會產生一些額外的行:
mysql> **SELECT year, country, product, SUM(profit)**
??? -> **FROM sales**
??? -> **GROUP BY year, country, product WITH ROLLUP;**
+------+---------+------------+-------------+
| year | country | product??? | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer?? |??????? 1500 |
| 2000 | Finland | Phone????? |???????? 100 |
| 2000 | Finland | NULL?????? |??????? 1600 |
| 2000 | India?? | Calculator |???????? 150 |
| 2000 | India?? | Computer?? |??????? 1200 |
| 2000 | India?? | NULL?????? |??????? 1350 |
| 2000 | USA???? | Calculator |????????? 75 |
| 2000 | USA???? | Computer?? |??????? 1500 |
| 2000 | USA???? | NULL?????? |??????? 1575 |
| 2000 | NULL??? | NULL?????? |??????? 4525 |
| 2001 | Finland | Phone????? |????????? 10 |
| 2001 | Finland | NULL?????? |????????? 10 |
| 2001 | USA???? | Calculator |????????? 50 |
| 2001 | USA???? | Computer?? |??????? 2700 |
| 2001 | USA???? | TV???????? |???????? 250 |
| 2001 | USA???? | NULL?????? |????? ??3000 |
| 2001 | NULL??? | NULL?????? |??????? 3010 |
| NULL | NULL??? | NULL?????? |??????? 7535 |
+------+---------+------------+-------------+
對于這個問詢, 添加ROLLUP 子句使村輸出結果包含了四層分析的簡略信息,而不只是一個下面是怎樣解釋? ROLLUP輸出:
- 一組給定的年份和國家的每組產品行后面, 會產生一個額外的總計行, 顯示所有產品的總值。這些行將產品列設置為 NULL。
- 一組給定年份的行后面,會產生一個額外的總計行,顯示所有國家和產品的總值。這些行將國家和產品列設置為? NULL。
- 最后, 在所有其它行后面,會產生一個額外的總計列,顯示所有年份、國家及產品的總值。 這一行將年份、國家和產品列設置為 NULL。
**使用ROLLUP 時的其它注意事項 **
以下各項列出了一些MySQL執行ROLLUP的特殊狀態:?
當你使用 ROLLUP時, 你不能同時使用 ORDER BY子句進行結果排序。換言之, ROLLUP 和ORDER BY 是互相排斥的。然而,你仍可以對排序進行一些控制。在 MySQL中, GROUP BY 可以對結果進行排序,而且你可以在GROUP BY列表指定的列中使用明確的 ASC和DESC關鍵詞,從而對個別列進行排序。 (不論如何排序被ROLLUP添加的較高級別的總計行仍出現在它們被計算出的行后面)。
LIMIT可用來限制返回客戶端的行數。LIMIT 用在 ROLLUP后面, 因此這個限制 會取消被ROLLUP添加的行。例如:
mysql> **SELECT year, country, product, SUM(profit)**
??? -> **FROM sales**
??? -> **GROUP BY year, country, product WITH ROLLUP**
??? -> **LIMIT 5;**
+------+---------+------------+-------------+
| year | country | product??? | SUM(profit) |
+------+---------+------------+-------------+
| 2000 | Finland | Computer?? |?? ?????1500 |
| 2000 | Finland | Phone????? |???????? 100 |
| 2000 | Finland | NULL?????? |??????? 1600 |
| 2000 | India?? | Calculator |???????? 150 |
| 2000 | India?? | Computer?? |??????? 1200 |
+------+---------+------------+-------------+
將ROLLUP同 LIMIT一起使用可能會產生更加難以解釋的結果,原因是對于理解高聚集行,你所掌握的上下文較少。
在每個高聚集行中的NULL 指示符會在該行被送至客戶端時產生。服務器會查看最左邊的改變值后面的GROUP BY子句指定的列。對于任何結果集合中的,有一個詞匹配這些名字的列, 其值被設為 NULL。(若你使用列數字指定了分組列,則服務器會通過數字確定將哪個列設置為 NULL)。
由于在高聚集行中的 NULL值在問詢處理階段被放入結果集合中,你無法將它們在問詢本身中作為NULL值檢驗。例如,你無法將 HAVING product IS NULL 添加到問詢中,從而在輸出結果中刪去除了高聚集行以外的部分。?
另一方面, NULL值在客戶端不以 NULL 的形式出現, 因而可以使用任何MySQL客戶端編程接口進行檢驗。
### 12.10.3.?具有隱含字段的GROUP BY
MySQL 擴展了 GROUP BY的用途,因此你可以使用SELECT 列表中不出現在GROUP BY語句中的列或運算。這代表 “對該組的任何可能值 ”。你可以通過避免排序和對不必要項分組的辦法得到它更好的性能。例如,在下列問詢中,你無須對customer.name 進行分組:
mysql> **SELECT order.custid, customer.name, MAX(payments)**
??? ->??????? **FROM order,customer**
??? ->??????? **WHERE order.custid = customer.custid**
??? ->??????? **GROUP BY order.custid;**
在標準SQL中, 你必須將 customer.name添加到 GROUP BY子句中。在MySQL中, 假如你不在ANSI模式中運行,則這個名字就是多余的。
假如你從 GROUP BY 部分省略的列在該組中不是唯一的,那么*不要使用這個功能*! 你會得到非預測性結果。
在有些情況下,你可以使用MIN()和MAX() 獲取一個特殊的列值,即使他不是唯一的。下面給出了來自包含排序列中最小值的列中的值:
SUBSTR(MIN(CONCAT(RPAD(sort,6,' '),column)),7)
See [ 3.6.4節,“擁有某個字段的組間最大值的行”](# "3.6.4.?The Rows Holding the Group-wise Maximum of a Certain Field").
注意,假如你正在嘗試遵循標準 SQL, 你不能使用GROUP BY或 ORDER BY子句中的表達式。你可以通過使用表達式的別名繞過這一限制:?
mysql> **SELECT id,FLOOR(value/100) AS val **
??? -> **FROM *tbl_name***
??? -> **GROUP BY id, val ORDER BY val;**
然而, MySQL允許你使用GROUP BY 及 ORDER BY 子句中的表達式。例如:
mysql> **SELECT id, FLOOR(value/100) FROM *tbl_name* ORDER BY RAND();**
這是MySQL參考手冊的翻譯版本,關于MySQL參考手冊,請訪問[dev.mysql.com](http://dev.mysql.com/doc/mysql/en)。 原始參考手冊為英文版,與英文版參考手冊相比,本翻譯版可能不是最新的。
- 目錄
- 前言
- 1. 一般信息
- 2. 安裝MySQL
- 3. 教程
- NoName
- 4. MySQL程序概述
- 5. 數據庫管理
- 6. MySQL中的復制
- 7. 優化
- 8. 客戶端和實用工具程序
- 9. 語言結構
- 10. 字符集支持
- 11. 列類型
- 12. 函數和操作符
- 13. SQL語句語法
- 14. 插件式存儲引擎體系結構
- 15. 存儲引擎和表類型
- 16. 編寫自定義存儲引擎
- 17. MySQL簇
- 18. 分區
- 19. MySQL中的空間擴展
- 20. 存儲程序和函數
- 21. 觸發程序
- 22. 視圖
- 23. INFORMATION_SCHEMA信息數據庫
- 24. 精度數學
- 25. API和庫
- 26. 連接器
- 27. 擴展MySQL
- A. 問題和常見錯誤
- B. 錯誤代碼和消息
- C. 感謝
- D. MySQL變更史
- E. 移植到其他系統
- F. 環境變量
- G. MySQL正則表達式
- H. MySQL中的限制
- I. 特性限制
- J. GNU通用公共許可
- K. MySQL FLOSS許可例外
- 索引