存儲在數據庫表中的數據通常不是應用程序所須要的格式。好比:html
在上面舉的例子中,存儲在表中的數據都不是應用程序所須要的。咱們須要直接數據庫中檢索出轉換、計算或格式化過的數據;而不是檢索出數據,而後在客戶機應用程序或報告程序中從新格式化。mysql
因此就須要計算字段。計算字段並不實際存儲於數據庫表中,而是運行時在SELECT語句內建立的。程序員
這裏的字段(field)基本上跟列(column)的意思相同,常常互換使用,不過數據庫列通常稱爲列,而術語字段一般用在計算字段的鏈接上。算法
可在SQL語句內完成的許多轉換和格式化工做均可以直接在客戶機應用程序內完成。可是通常來講,在數據庫服務器上完成這些操做比在客戶機中完成要快得多,由於DBMS是設計來快速地完成這種處理的。sql
舉一個建立由兩列組成的標題的簡單例子。數據庫
vendors表包含供應商名和位置信息。假如要生成一個供應商報表,須要在供應商的名字中按照name(location)這樣的格式列出供應商的位置。express
此報表須要單個值,而表中數據存儲在兩個列vend_name和vend_country中。此外,須要用括號將vend_country括起來,這些東西都沒有明確存儲在數據庫表中。來看看如何用SELECT來編寫這樣的格式。服務器
拼接(concatenate)將值聯結到一塊兒構成單個值。函數
解決的方法就是將兩個列拼接起來。在MySQL的SELECT語句中,可以使用CONCAT()函數來拼接兩個列。工具
多數DBMS使用+或者||來實現拼接,而MySQL則使用Concat()函數來實現。當把SQL語句轉換成MySQL語句時必定要把這個區別銘記在心。
結果:
SELECT CONCAT(vend_name, '(', vend_country, ')') FROM vendors ORDER BY vend_name;
輸出:
+-------------------------------------------+ | CONCAT(vend_name, '(', vend_country, ')') | +-------------------------------------------+ | ACME(USA) | | Anvils R Us(USA) | | Jet Set(England) | | LT Supplies(USA) | +-------------------------------------------+ 4 rows in set (0.06 sec)
解釋:
你拿上面那條語句去執行,會發現新計算出的列名,列名好長並且列名的意義不能明確看出。實際上它是沒有名稱,它只是一個值。若是僅在SQL查詢工具中查看一下結果,這樣沒什麼很差。可是,一個未命名的列不能用於客戶機應用中,由於客戶機沒有辦法引用它。這時候SQL就引出別名。
別名(alias)是一個字段或值的替換名。別名用AS關鍵字賦予。
使用別名修改上面的SQL語句
SELECT CONCAT(vend_name, '(', vend_country, ')') AS vend_title FROM vendors ORDER BY vend_name;
AS也可省略,只要在須要重命名的後面空一格。
SELECT CONCAT(vend_name, '(', vend_country, ')') vend_title FROM vendors ORDER BY vend_name;
輸出:
+------------------+ | vend_title | +------------------+ | ACME(USA) | | Anvils R Us(USA) | | Jet Set(England) | | LT Supplies(USA) | +------------------+ 4 rows in set (0.06 sec)
這樣任何客戶機均可以按別名引用這個列,看起來是一個實際的表列同樣。
別名不止用於計算字段中,還能夠在實際的表列名包含不符合規定的字符(含空格)時從新命名它,在原來的名字含混或容易誤解時擴充它,等。但記住,並非真正會去重命名錶中的實際列名。
別名有時候也稱爲導出列(derived column),無論稱爲何,它們所表明的都是相同的東西。
計算字段的另外一常見用途是讀檢索出的數據進行算術計算。好比,一個訂單表order中含有物品價格price和物品數量quantity,須要求物品總價格。那麼只須要 物品價格乘以物品數據便可。
SELECT order_id, order_price*order_quantiry AS expanded_price FROM order;
MySQL算術操做符:+、-、*、/。
SELECT可用經過使用計算字段來測試。
SELECT 2*3;
小結:介紹了計算字段以及如何建立計算字段。此外還學瞭如何建立和使用別名,以便應用程序能引用計算字段。
SQL支持利用函數來處理數據。
可移植性(portable): 能運行在多個系統上的代碼。
多數SQL語句是可移植的,在SQL實現之間有差別時,這些差別一般不那麼難處理。而函數的可移植性卻不強。幾乎每種主要的DBMS的實現都支持其餘實現不支持的函數,並且有時差別還很大。
爲了代碼的可移植性,不少SQL程序員不同意使用特殊實現的功能。雖然這樣有好處,可是不使用這些函數,編寫某些應用程序代碼會很難。
若是決定使用函數,應該保證作好代碼註釋,以便之後你(或其餘人)能確切地知道所編寫的SQL代碼的含義。
大多數SQL實現支持如下類型的函數
以前已經介紹TRIM():去空格的函數。相似的函數以下:
參考:菜鳥教程
函數 | 說明 | 演示 |
---|---|---|
LEFT(s,n) | 返回字符串 s 的前 n 個字符 | 返回字符串 runoob 中的前兩個字符:SELECT LEFT('runoob',2) -- ru |
RIGHT(s,n) | 返回字符串 s 的後 n 個字符 | 返回字符串 runoob 的後兩個字符:SELECT RIGHT('runoob',2) -- ob |
LOWER(s) | 將串轉換爲小寫 | 把字符串 Runoob 全轉小寫: SELECT LOWER('Runoob') -- runoob |
UPPER(s) | 將串轉換爲大寫 | 返回字符串 runoob 全轉小寫:SELECT UPPER('Runoob') -- RUNOOB |
TRIM(s) | 去掉串的左右空格 | 去掉字符串 空格runoob空格 的空格:SELECT TRIM(' runoob ') -- runoob |
LTRIM(s) | 去掉串左邊的空格 | 去掉字符串 空格runoob空格 的左空格:SELECT LTRIM(' runoob ') -- runoob空格 |
RTRIM(s) | 去掉串右邊的空格 | 去掉字符串 空格runoob空格 的右空格:SELECT RTRIM(' runoob ') -- 空格runoob |
SOUNDEX() | 返回串的SOUNDEX值 | 看下面的解釋 |
SUBSTRING(s, start, length) | 從字符串 s 的 start 位置截取長度爲 length 的子字符串 | 從字符串 RUNOOB 中的第 2 個位置截取 3個 字符:SELECT SUBSTRING("RUNOOB", 2, 3) AS ExtractString; -- UNO |
LOCATE(s1,s) | 從字符串 s 中獲取 s1 的開始位置 | 獲取 b 在字符串 abc 中的位置:SELECT LOCATE('st','myteststring'); -- 5 返回字符串 abc 中 b 的位置:SELECT LOCATE('b', 'abc') -- 2 |
LENGTH() | 返回串的長度 | 返回字符串 runoob 的長度:SELECT LENGTH('runoob') -- 6 |
上面的SOUNDEX須要進一步解釋:SOUNDEX是一個而將任何文本串轉換爲描述其語音表示的字母數字模式的算法。SOUNDEX考慮了相似的發音字符和音節,使得能對串進行發音比較而不是字母比較。雖然SOUNDEX不是SQL概念,但MySQL(就像很大DBMS同樣)都提供對SOUNDEX的支持。
好比,建立一張表名爲customers,表中包含顧客(cust_name)和聯繫名(cust_contact)。
CREATE TABLE customers( cust_name varchar(20) PRIMARY KEY, cust_contact varchar(20) );
如今假設有一個顧客Coyote Inc. , 其聯繫名爲 Y.Lee。但若是這是輸入錯誤的結果,此聯繫名實際應該是Y.Lie,怎麼辦?顯然,按正確的聯繫名搜索不會返回數據,以下:
SELECT cust_name, cust_contact FROM customers WHERE cust_contact = 'Y.Lie';
輸出:
Empty set
如今試下使用SOUNDEX()函數進行搜索,它匹配全部發音相似於Y.Lie的聯繫名:
SELECT cust_name, cust_contact FROM customers WHERE SOUNDEX(cust_contact) = SOUNDEX('Y.Lie');
輸出:
+-------------+--------------+ | cust_name | cust_contact | +-------------+--------------+ | Coyote Inc. | Y.Lee | +-------------+--------------+ 1 row in set (0.05 sec)
在這個例子中,WHERE子句使用SOUNDEX()函數來轉換cust_contact列值和搜索串爲它們的SOUNDEX值。由於Y.Lee和Y.lie發音類似,因此它們的SOUNDEX值匹配,所以WHERE子句正確地過濾了所需的數據。
日期和時間採用相應的數據類型和特殊的格式存儲,以便快速和有效地排序或過濾,並節省物理存儲空間。
通常,應用程序不使用來存儲日期和時間的格式,所以日期和時間函數老是被用來讀取、統計和處理這些值。因此,日期和時間函數在MySQL語言中很重要。
表格轉載:菜鳥教程
函數 | 說明 | 演示 |
---|---|---|
ADDDATE(d,n) | 計算起始日期 d 加上 n 天的日期 | SELECT ADDDATE("2020-01-15", 3); 或 SELECT ADDDATE("2020-01-15", INTERVAL 3 DAY); ->(2020-01-18) |
ADDTIME(t,n) | 時間 t 加上 n 秒的時間 | SELECT ADDTIME('2011-11-11 11:11:11', 5); ->2011-11-11 11:11:16 (秒) |
CURDATE() | 返回當前日期 | SELECT CURDATE(); ->2020-01-15 |
CURTIME() | 返回當前時間 | SELECT CURTIME(); ->16:41:01 |
DATE() | 從日期或日期時間表達式中提取日期值 | SELECT DATE("2020-01-15"); ->2020-01-15 |
DATEDIFF(d1,d2) | 計算日期 d1->d2 之間相隔的天數 | SELECT DATEDIFF("2020-01-15","2020-01-4"); ->11(前面的日期減去後面的日期) |
DATE_ADD(d,INTERVAL expr type) | 計算起始日期 d 加上一個時間段後的日期 | SELECT ADDDATE('2011-11-11 11:11:11',1); -> 2011-11-12 11:11:11 (默認是天) SELECT ADDDATE('2011-11-11 11:11:11', INTERVAL 5 MINUTE); -> 2011-11-11 11:16:11 (TYPE的取值與上面那個列出來的函數相似) |
DATE_FORMAT(d,f) | 按表達式 f的要求顯示日期 d | SELECT DATE_FORMAT('2011-11-11 11:11:11','%Y-%m-%d %r') -> 2011-11-11 11:11:11 AM |
DAY(d) | 返回日期值 d 的日期部分 | SELECT DAY("2020-01-15"); -> 15 |
DAYOFWEEK(d) | 日期 d 今天是星期幾,1 星期日,2 星期一,以此類推 | SELECT DAYOFWEEK("2020-01-15"); -> 4 |
HOUR(t) | 返回 t 中的小時值 | SELECT HOUR("2020-01-15 17:21"); -> 17 |
MINUTE(t) | 返回 t 中的分鐘值 | SELECT MINUTE("2020-01-15 17:21"); -> 21 |
MONTH(d) | 返回日期d中的月份值,1 到 12 | SELECT MONTH("2020-01-15 17:21"); -> 1 |
NOW() | 返回當前日期和時間 | SELECT NOW(); -> 2020-01-15 17:24:18 |
MICROSECOND(date) | 返回日期參數所對應的微秒數 | SELECT MICROSECOND("2017-06-20 09:34:00.000023"); -> -> 23 |
TIME(expression) | 提取傳入表達式的時間部分 | SELECT TIME("19:30:10"); -> 19:30:10 |
YEAR(t) | 返回t日期中的年份 | SELECT YEAR("2020-01-15 17:21"); -> 2020 |
更多參考:菜鳥教程
須要注意的是MySQL使用的日期格式。不管是何時指定一個日期,或是插入或更新等,日期必須爲格式yyyy-mm-dd。因此,2020年1月15號,給出的是2020-01-15.雖然其餘的日期格式可能也行,但這是首選的日期格式,由於它排除了多義性(如,04/05/06是2006年5月4號仍是2006年4月5號或...)。
應該老是使用4位數字的年份。MySQL雖然支持2位數字的年份,好比處理00-69位2000-2069。雖然它們多是打算要的年份,但使用完整的4位數字年份更可靠。
在數據庫表中檢索時間日期,好比:
SELECT cust_id, order_num FROM orders WHERE order_date = '2005-09-01';
這樣寫的 order_date = '2005-09-01' 可靠嗎?若是order_date的數據類型是datetime,這種類型存儲日期及時間值,那麼在例表中的值全都具備時間值00:00:00,但實際上極可能並不老是這樣。若是用當前日期和時間存儲訂單日期(所以咱們得知道訂單日期和下訂單當前的時間),怎麼辦??好比,存儲的order_date值爲2005-09-01 11:30:05,則WHERE order_date = '2005-09-01'就失敗。
解決的方式:讓MySQL僅將給出的日期與列中的日期部分進行比較,而不是將給出的日期與整個列值進行比較。因此得使用DATE()函數。DATE(order_date)表示MySQL僅提取列的日期部分,因此修改以下:
SELECT cust_id, order_num FROM orders WHERE DATE(order_date) = '2005-09-01';
因此,對於日期的數據要特別注意,若是要的是日期,使用DATE(),若是要的是天,使用DAY(),若是要的是月,使用MONTH()等。最好明確要的是什麼格式的日期,即便知道相應的列只包含日期也應該加上函數。
還有一種日期比較須要說明。若是要檢索2005年9月下的全部訂單,怎麼辦??簡單的相等測試確定不行,由於它也要匹配月份中的天數。提供如下的解決方法:
SELECT cust_id, order_num FROM orders WHERE DATE(order_date) BETWEEN '2005-09-01' AND '2005-09-30';
其中,BETWEEN操做符用來把2005-09-01和2005-09-30定義爲一個要匹配的日期範圍。
還有另外一種:
SELECT cust_id, order_num FROM orders WHERE YEAR(order_date) = 2005 AND MONTH(order_date) = 9;
解釋:YEAR()是一個從日期(或日期時間)中返回年份的函數。相似,MONTH從日期中返回月份。所以WHERE YEAR(order_date) = 2005 AND MONTH(order_date) = 9檢索出order_date爲2005年9月的全部行。
數值處理函數僅處理數值數據。通常主要用於代數、三角或幾何運算。
在主要DBMS的函數中,數值函數是最統一最一致的函數。
函數 | 說明 |
---|---|
ABS(t) | 返回數t的絕對值 |
COS(t) | 返回角度爲t的餘弦 |
EXP(t) | 返回數t的指數值 |
MOD(a, b) | 返回除操做(a/b)的餘數 = (a%b) |
PI() | 返回圓周率 |
RAND() | 返回一個隨機數 |
SIN(t) | 返回角度爲t的正弦 |
SQRT(t) | 返回數t的平方根 |
TAN(t) | 返回角度爲t的正切 |
小結:介紹瞭如何使用SQL的數據處理函數,主要注意日期函數的使用。這些函數不須要死記硬背,忘了就拿出來看。固然,最好簡單的函數就記一記,好比:ABS()、SQRT()、YEAR()、HOUR()、DAY()等這些。