學習筆記,來源:實驗樓 ,鏈接: https://www.shiyanlou.com/courses/9

一、日期計算:
1、要想確定每個寵物有多大,可以使用函數TIMESTAMPDIFF()計算當前日期的年和出生日期之間的差也可以按照直接使用語句
(YEAR(CURDATE())-YEAR(birth))計算,其中函數
CURDATE()是計算當前的日期。如果當前日期的日歷年比出生日期早,則減去一年。以下代碼是查詢每個寵物的出生日期、當前日期和年齡(以年作為計算單位),其中關鍵字age是年齡這個計算結果的標簽。
SELECT name, birth, CURDATE(),TIMESTAMPDIFF(YEAR,birth,CURDATE()) AS age FROM pet; SELECT name, birth, CURDATE(), (YEAR(CURDATE())-YEAR(birth)) - (RIGHT(CURDATE(),5)<RIGHT(birth,5)) AS age FROM pet ORDER BY name;
YEAR()提取日期的年部分,
RIGHT()提取日期最右面5個字符的MM-DD (月份和日期)部分。
2、查詢來確定已經死亡動物的死亡年齡。你通過檢查death值是否為NULL來確定是哪些動物已經死亡,然后對於那些非NULL值的動物,需要計算出death和birth值之間的差來知道他們在這個世界上所存在的時間:
SELECT name, birth, death, (YEAR(death)-YEAR(birth)) - (RIGHT(death,5)<RIGHT(birth,5)) AS age FROM pet WHERE death IS NOT NULL ORDER BY age;
查詢使用
death IS NOT NULL而非death != NULL,因為NULL是特殊的值,不能使用普通比較符來比較。
3、哪個動物下個月過生日怎么辦?對於這類計算,年和天是無關的,你只需要提取birth列的月份部分。MySQL提供幾個日期方面的提取函數,例如
YEAR()、MONTH()和
DAYOFMONTH()。在這里MONTH()是我們需要的函數。為了觀察它的實現原理,可以運行以下簡單的查詢顯示birth和MONTH(birth)的值:
SELECT name, birth FROM pet WHERE MONTH(birth) = MONTH(DATE_ADD(CURDATE(),INTERVAL 1 MONTH));、
DATE_ADD()允許在一個給定的日期上加上時間間隔。如果在NOW()值上加上一個月,然后用MONTH()提取月份,產生生日所在月份
4、完成該任務的另一個方法是加1得出當前月份的下一個月(在使用取模函數
MOD()后,如果月份當前值是12,則“返回”到值0):
SELECT name, birth FROM pet WHERE MONTH(birth) = MOD(MONTH(CURDATE()), 12) + 1;
注意,MONTH返回在1和12之間的一個數字,且MOD(something,12)返回在0和11之間的一個數字,因此必須在MOD()后加1,否則我們將從11月(11)跳到1月(1)。
二、模式匹配:
1、MySQL提供標准的SQL模式匹配,以及一種基於類Unix里的程序如vi、grep和sed里的擴展正則表達式模式匹配的格式。 SQL模式匹配允許你使用
“_”匹配任何單個字符,而
“%”匹配任意數目字符(包括零字符)。在 MySQL中,SQL的模式默認是忽略大小寫的。下面給出一些例子。注意使用SQL模式時,不能使用=或!=;而應使用LIKE或NOT LIKE比較操作符。
要想找出以“b”開頭的名字的動物信息:
mysql> SELECT * FROM pet WHERE name LIKE 'b%';
要想找出以“fy”結尾的名字:
mysql> SELECT * FROM pet WHERE name LIKE '%fy';
要想找出包含“w”的名字:
mysql> SELECT * FROM pet WHERE name LIKE '%w%';
要想找出正好包含5個字符的名字,使用“_”模式字符:
mysql> SELECT * FROM pet WHERE name LIKE '_____';
2、由MySQL提供的模式匹配的其它類型是使用擴展正則表達式。當你對這類模式進行匹配測試時,使用
REGEXP和
NOT REGEXP操作符(或
RLIKE和
NOT RLIKE,它們是同義詞)。
擴展正則表達式的一些字符是:
- ‘.’匹配任何單個的字符。
- 字符類“[...]”匹配在方括號內的任何字符。例如,“[abc]”匹配“a”、“b”或“c”。為了命名字符的范圍,使用一個“-”。“[a-z]”匹配任何字母,而“[0-9]”匹配任何數字。
- “ ”匹配零個或多個在它前面的字符。例如,“x”匹配任何數量的“x”字符,“[0-9]”匹配任何數量的數字,而“.”匹配任何數量的任何字符。
如果
REGEXP模式與被測試值的任何地方匹配,模式就匹配(這不同於LIKE模式匹配,只有與整個值匹配,模式才匹配)。 為了定位一個模式以便它必須匹配被測試值的開始或結尾,在模式開始處使用“^”或在模式的結尾用“$”。 為了說明擴展正則表達式如何工作,下面使用REGEXP重寫上面所示的LIKE查詢:
為了找出以“b”開頭的名字,使用“^”匹配名字的開始:
mysql> SELECT * FROM pet WHERE name REGEXP '^b';
如果你想強制使REGEXP比較區分大小寫,使用BINARY關鍵字使其中一個字符串變為二進制字符串。該查詢只匹配名稱首字母的小寫‘b’。
mysql> SELECT * FROM pet WHERE name REGEXP BINARY '^b';
為了找出以“fy”結尾的名字,使用“$”匹配名字的結尾:
mysql> SELECT * FROM pet WHERE name REGEXP 'fy$';
為了找出包含一個“w”的名字,使用以下查詢:
mysql> SELECT * FROM pet WHERE name REGEXP 'w';
3、既然如果一個正則表達式出現在值的任何地方,他就會被模式匹配,就不必在先前的查詢中在模式的兩側放置一個通配符以使得它匹配整個值,就像你使用了一個SQL模式那樣。
為了找出包含正好5個字符的名字,使用“^”和“$”匹配名字的開始和結尾,和5個“.”實例在兩者之間:
mysql> SELECT * FROM pet WHERE name REGEXP '^.....$';
你也可以使用“{n}”重復n次操作符,重寫前面的查詢:
mysql> SELECT * FROM pet WHERE name REGEXP '^.{5}$';
三、計算行數:
計算你擁有動物的總數目與“在pet表中有多少行?”是同樣的問題,因為每個寵物都對應一條記錄。COUNT(*)函數計算行數,所以計算動物數目的查詢應為:
mysql> SELECT COUNT(*) FROM pet;
如果你想要知道每個主人有多少寵物,你也可以使用COUNT(*)函數:
mysql> SELECT owner, COUNT(*) FROM pet GROUP BY owner;
注意,使用GROUP BY對每個owner的所有記錄分組,沒有它,你會得到錯誤消息:
mysql> SELECT owner, COUNT(*) FROM pet; ERROR 1140 (42000): Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause
COUNT(*)和GROUP BY以各種形式分類你的數據。下列例子顯示出以不同方式進行動物普查操作。
查看每種動物的數量:
mysql> SELECT species, COUNT(*) FROM pet GROUP BY species;
查看每種性別的動物數量:
mysql> SELECT sex, COUNT(*) FROM pet GROUP BY sex;
按種類和性別組合分類的動物數量:
mysql> SELECT species, sex, COUNT(*) FROM pet GROUP BY species, sex;
若使用COUNT(*),你不必檢索整個表。例如, 當只對狗和貓進行查詢時,應為:
mysql> SELECT species, sex, COUNT(*) FROM pet WHERE species = 'dog' OR species = 'cat' GROUP BY species, sex;
或,如果你僅需要知道已知性別的按性別分組的動物數目:
mysql> SELECT species, sex, COUNT(*) FROM pet WHERE sex IS NOT NULL GROUP BY species, sex;
四、使用1個以上的表
pet表追蹤你擁有的寵物。如果你想要記錄其它相關信息,例如在他們看獸醫的情況或后代出生的情況,那么你需要另外的表。這張表應該擁有些什么呢?它需要:
需要包含寵物名字以便你知道每個發生的事件屬於哪個動物。
需要一個日期以便你知道事件是什么時候發生的。
需要一個描述事件的字段。
如果你想要對事件進行分類,則需要一個事件類型字段。
綜上所述,
event表的CREATE TABLE語句應為:
mysql> CREATE TABLE event (name VARCHAR(20), date DATE, type VARCHAR(15), remark VARCHAR(255));
類似於於pet表,最簡單的方法是創建一個用定位符分隔的文本文件來加載載初始記錄:


采用如下方式加載記錄:
mysql> LOAD DATA LOCAL INFILE '/home/shiyanlou/Desktop/event.txt' INTO TABLE event;


由於你已經在
pet表上的查詢中學到了一定的知識,你應該能執行對
event表中記錄的檢索;原理是一樣的。但是有沒有event表本身不能回答你可能問的問題呢?
當寵物們生了了一窩小動物時,假定你想要找出這時候每只寵物的年齡。我們前面看到了如何通過兩個日期計算年齡。event表中有母親的生產日期,但是為了計算母親的年齡,你需要她的出生日期,存儲在pet表中。說明查詢需要兩個表:
mysql> SELECT pet.name, -> (YEAR(date)-YEAR(birth)) - (RIGHT(date,5)<RIGHT(birth,5)) AS age, -> remark -> FROM pet, event -> WHERE pet.name = event.name AND event.type = 'litter';


關於該查詢要注意以下幾件事:
FROM子句連接兩個表,因為查詢需要從兩個表中提取信息。
當從多個表組合(聯結)信息時,你需要指定其中一個表中的列明以期匹配其它表的列名。這很簡單,因為它們都有一個name列,查詢可以通過使用WHERE子句基於name值來匹配兩個表中的記錄。
因為name列都存在兩個表中,因此
當引用該列時,一定要指定是哪個表,把表名附在列名前即可以實現。 如果你想要將一個表的記錄與該表的其它記錄進行比較,可以將該表聯結到自身。例如,為了在你的寵物之中選擇繁殖中的配偶,你可以用pet表聯結自身來進行相同種類的雄雌配對:
mysql> SELECT p1.name, p1.sex, p2.name, p2.sex, p1.species -> FROM pet AS p1, pet AS p2 -> WHERE p1.species = p2.species AND p1.sex = 'f' AND p2.sex = 'm';
在這個查詢中,我們為表名指定別名p1和p2以便能引用它們的列並且使得每一個列的引用更直觀。
五、獲得數據庫和表的信息
1、如果你忘記數據庫或表的名字,或給定的表的結構是什么(例如,它的列叫什么),怎么辦?MySQL提供一些語句解決這個問題。 你已經知道SHOW DATABASES可以列出由服務器管理的所有數據庫。為了找出當前選擇了哪個數據庫,使用
DATABASE()函數:
mysql> SELECT DATABASE();
如果你還沒選擇任何數據庫,結果是
NULL。
2、為了找出當前的數據庫包含什么表(例如,當你不能確定一個表的名字),使用這個命令:
mysql> SHOW TABLES;
3、如果你想要知道一個表的結構,可以使用
DESCRIBE命令;它顯示表中每個列的信息:
mysql> DESCRIBE pet;
Field顯示列名字,
Type是列的數據類型,
Null表示列是否能包含NULL值,
key顯示列是否被索引而
Default指定列的默認值。
如果表有索引,SHOW INDEX FROM tbl_name生成有關索引的信息。