MySQL數據庫基礎(筆記整理一)

數據庫的組織結構

MySQL屬於關係數據庫管理系統(Relational Database Management System, RDBMS)mysql

  • 數據庫(Database,DB)即一個用來存放信息的倉庫,他們構造簡單,遵照必定規則;
  • 數據庫裏的數據集合都存放在數據表(table)裏;
  • 數據表由數據行(row)和數據列(column)構成;
  • 一個數據行就是數據表裏的一條記錄(record);
  • 記錄能夠包含多個信息項,數據表裏的每個數據列都對應一個信息項。
  • 管理系統(Management System, MS) 指的是用來對數據進行插入、檢索、修改、刪除等操做的軟件。
  • 關係(Relational ,R)表示RDBMS是DBMS中的一種,RDBMS專長是把分別存放在兩個數據表裏的信息聯繫起來(匹配),這種聯繫是經過查找兩個數據表的共同元素來實現的。RDBMS的強項在於它能方便地抽取出數據表裏的數據並把它們與其餘數據表裏的信息結合起來爲那些單獨利用某個數據表沒法找到答案的問題提供答案。

數據庫的查詢語言

爲了與MySQL交互,你須要使用一種名爲SQL(Structed Query Language,結構化查詢語言)的語言。SQL是標準化數據庫語言,SQL的各類語句是它可以搞效率地與你的數據庫盡心互動。web

MySQL的體系結構

MySQL採用的是C/S(客戶/服務器)體系結構。正則表達式

  • mysqld (MySQL的服務器程序 ),運行在存放你數據庫的機器上。負責在網絡上監聽並處理來自客戶的服務請求,並根據這些請求去訪問數據庫的內容,再將有關信息回傳給客戶。
  • Client (MySQL的客戶程序),負責鏈接到數據庫服務器,並經過向服務器發出命令來告知它們須要哪些信息。 MySQL的「客戶/服務器」體系結構的優勢:
  1. 併發控制,由服務器提供,於是不會出現兩個用戶同時修改一條記錄的現象。
  2. 你沒必要非要在存放你數據庫的那臺機器上登陸MySQL。

建立MySQL用戶並設置訪問權限

首先以root的身份登陸MySQL,再用CREATE USER和GRANT語句新建一個MySQL用戶,並分配訪問數據庫的權限。sql

$ mysql -u root -p
Enter password: \*\*\*\*\*\*
mysql> CREATE USER 'example'@'localhost' IDENTIFIED BY '123456' ;
mysql> GRANT ALL ON webdata.* TO 'example'@'localhost' ;

mysql命令的-p選項會讓mysql提示MySQL的root用戶輸入密碼。假設你打算使用遠程登陸的方式管理數據庫,CREATE USER中的localhost就應該改成%(或者你要使用的另外一臺計算機的IP)shell

  • 在建立用戶帳號後,必須接着分配訪問權限。新建立的用戶帳號沒有訪問權限。它們能登陸MySQL,但看不到數據,也不能對任何數據庫進行操做。
  • 可使用 SHOW GRANTS FOR example; 查看用戶的權限
  • 使用GRANT語句,至少要給出:1)要授予的權限; 2)被授予訪問權限的數據庫或表; 3)用戶名
  • 屢次受權容許用逗號分隔,將多條GRANT語句連在一塊兒,如:GRANT SELECT, INSERT ON databse.* TO example;
  • 一樣要取消用戶的特定權限,能夠用REVOKE語句。(用法參考GRANT)
  • GRANT和REVOKE可在幾個層次上控制訪問權限:
  • 整個服務器 (GRANT ALL 和REVOKE ALL)
  • 整個數據庫( ON database.*)
  • 特定的表(ON database.table)
  • 特定的列
  • 特定的存儲過程
  • 在使用GRANT和REVOKE時,用戶帳號必須存在,但對所涉及的對象沒有這個要求。這容許DBA在建立數據庫和表以前設計和實現安全措施。

創建/斷開與MySQL服務器的鏈接

  • mysql -h host_name -p -u user_name [database]
  1. -h host_name 帶鏈接的服務器主機名。本地可省略。
  2. -u user_name 你的MySQL用戶名。
  3. -p 提示輸入MySQL口令。
  4. 鏈接經常使用的數據庫(沒必要在USE database)
  • quit/exit 便可斷開與MySQL的鏈接。

小技巧:數據庫

Linux下能夠將經常使用的mysql命令寫入 ~/.bashrc 例如,能夠將如下語句寫入 .bashrc編程

alias mysql-example='mysql -u example -p sample'
alias mysql-root='mysql -u root -p'
alias mysqlstart='sudo systemctl start mysqld'
alias mysqlstop='sudo systemctl stop mysqld'
alias mysqlstatus='sudo systemctl status mysqld'

在執行 source .bashrc ,再次鏈接MySQL數據庫只需輸入mysql-example便可鏈接到example用戶,而啓動/中止/查看,MySQL服務用上面的別名也會方便不少。安全


執行SQL語句

鏈接上服務器後,如今就能夠經過select語句進行相關的數據查詢了。利用mysql命令行的方式進行數據庫查詢很簡單:敲入有關命令,命令末尾以分號 ;\g 表示語句結束。事實上,這個過程是在你輸入完查詢語句以後,查詢命令將由mysql發往服務器執行,服務器對查詢進行處理並把其結果返回給mysql,最後由mysql將查詢結果顯示在屏幕上。 例如:bash

mysql> SELECT NOW();

上面這條語句將返回系統的當前日期和時間。上面說過,除了 分號 ; 之外 \g (表示go) 也能夠表示語句的結束。其實還可使用 \G (將會豎直排列顯示結果,每行一個值)服務器

mysql> SELECT NOW(), USER(), VERSION() \G
     NOW():    2018/10/07    17:21
    USER():    example@localhost
VERSION:     10.1.36 -MariaDB

若是查詢命令的輸出行比較短,以 \G 做爲查詢命令的結束符效果還不太明顯。但萬一輸出行比較長,在屏幕上顯示爲好幾行的時候,\G 結束符就能使屏幕輸出的內容更便於閱讀。

由於mysql必須等待語句結束符,因此咱們不必把查詢命令完整地寫在同一行上。例如:

mysql> SELECT NOW(),
    ->    USER(),
    ->    VERSION()
    ->    ;

假如,我已經輸入了好幾行查詢命令但卻忽然發現不該該執行它,輸入 \c 便可取消它。有一點特別注意,當查詢命令的 '未配對的的狀況下,應該用 '\c 來取消執行。

批處理的方式執行SQL語句

能夠用SQL腳本的方式,讓mysql從文件讀入數據和命令也不是經過鍵盤的輸入。這樣的處理方式,在數據量比較大的時候,要比在命令行插入數據高效的多。咱們能夠經過shell的輸入重定向功能,將SQL語句寫入一個名爲 mysqlscript.sql的文件中,經過下面的方式執行它們:

$ mysql < mysqlscript.sql

或者是在msql命令行中以 source 的方式執行sql腳本:

mysql> source /home/example/mysqlscript.sql

須要注意的是,mysqlscript.sql 要給出它的絕對路徑。經過這樣的方法,咱們能夠方便的批量建立一系列表或者從不少文件中LOAD 數據。


建立數據庫

建立數據庫:首先用mysql鏈接服務器,以root的身份建立數據庫 CREATE DATABASE database1; 任什麼時候候都應該避免直接登陸root去操做數據庫。 建立數據庫以後,並不意味着已經把它選定爲當前的默認數據庫了。你須要用 USE database1把它設置爲當前默認數據庫。選定數據庫的另外一種方法是在上一篇中提到的在啓動mysql的命令行上給出數據庫的名字:

$ mysql -u example -p database1

建立數據表

建立數據表,能夠用CREATE TABLE語句來完成,這條語句的格式以下:

CREATE TABLE tbl_name (column_specs); 其中,tbl_name 是表名,column_specs則是該數據庫裏的各個數據列以及各類索引的定義。索引可以加快信息的檢索速度。

CREATE TABLE customers
(     
    stu_id      int    UNSIGNED    NOT NULL     AUTO_INCREMENT,
    stu_name    char(50)  NOT NULL ,
    stu_address char(50)  NULL ,                                                
    stu_city    char(50)  NULL ,
    stu_contact char(50)  NULL ,
    stu_email   char(255) NULL ,
    stu_gradate    date    NOT NULL,
   PRIMARY KEY (stu_id)
   ) ENGINE=InnoDB;

上面就是一個建立數據表的CREATE TABLE語句,執行這條語句的方法有好幾種。能夠手動輸入,也能夠寫入create1.sql腳本中經過shell輸入重導向。

$ mysql -u example -p database1 < create1.sql

執行上面的命令時,須要切換到create1.sql下去執行,不然應該給出create1.sql的絕對路徑。

在Linux中執行這條語句時,mysql -u example -p能夠另起一個別名以此來簡化輸入。 固然你也能夠,在鏈接數據庫以後 source create1.sql的方式執行腳本,一樣能夠完成建立數據庫的操做。(source 後面要跟create1.sql的絕對路徑)

在上面的數據表中,大部分數據列的類型都是可變長度的字符串。只有兩個數據列例外,用來保存學號的stu_id和畢業期限的 stu_gradate 而數據列stu_id的值必須是惟一的。這也是爲何咱們用stu_id 來做爲上表的主鍵,而AUTO_INCREMENT當咱們沒有給出stu_id 列的值時,會自動生成下一個編號並賦值給這個數據列。數據表class的定義包含以下幾個部分:

  • INT 表示這個數據列將用來保存整數值
  • UNSIGNED 不容許出現負數
  • NOT NULL 必須填有數據,不得爲空
  • AUTO_INCREMENT 主鍵自增屬性
  • PRIMRY KEY (stu_id) 將數據列stu_id 設爲數據表主鍵
  • ENGINE=InnoDB 爲數據表的設置InnoDB引擎(支持事物處理)

當建立完數據表後,能夠用 DESCRIBE class ; 命令,查看class表相關的結構信息。 也能夠用 DESC class ; 查看,DESC是DESCRIBE的簡寫。

DESCRIBE class;
DESC class;
EXPLAIN class;
SHOW COLUMNS FROM class;
SHOW FIELDS FROM class;

上面這幾條語句實際上都是同樣,顯示class數據表的信息。 SHOW 還有其它更多的用法,例如:

SHOW COLUMNS FORM class LIKE '%id' ;

能夠將輸出內容限制爲特定的數據列。

SHOW TABLES;
SHOW DATABASES;
SHOW WARNINGS;

上面都是SHOW的用法,第一條SHOW語句表示列出數據庫中都有哪些數據表;第二條SHOW語句表示列出當前鏈接的服務器上的數據庫;最後一條用於在sql語句提示warnings時,查看wanrnings信息。

添加新的數據行

  • 利用INSERT語句添加數據
INSTERT INTO tbl_name VALUES(value1, value2,....);

mysql>    INSTERT INTO student VALUES(‘RYLE', 'M', NULL);

在MySQL中也能夠用一條INSERT 語句把多個數據行插入到數據表裏去,語法以下;

INSERT INTO tbl_name VALUES(...),(...),...;
mysql>    INSERT INTO student VALUES('Avery','F', NULL),('Nathan','M', NULL);

更可靠的INSERT語句是對數據列進行賦值,先給出數據列的名字,再列出它的值。語法以下:

INSERT INTO tbl_name (col_name1,col_name2,...) VALUES(value1, value2,...);
mysql>    INSERT INTO member (last_nmae,first_name)VALUES('Stein', 'Waldo');

這種形式一樣能夠一次插入多個記錄:

mysql>    INSERT INTO student (name,sex) VALUES('Abby','F'), ('Joseph','M');

沒有在INSERT語句中出現的數據列將被賦予默認值。例如:上面兩條語句沒有給出member_id的數據列的值,因此MySQL將把默認值NULL賦給它們。而AUTO_INCREMENT數據列,將賦給member_id 一個自動生成的下一個序列號。

還可使用包含col_name =value (非values) 的SET子句的INSERT語句給數據列賦值。

INSERT INTO member SET last_name =’Steim‘, first_name = ’Waldo‘ ;

一樣沒有出如今SET子句裏的數據列將被賦予爲默認值。這種形式的INSERT語句不容許一次插入多個數據行。

  • 經過從文件中讀取來添加新行

把數據記錄加載到數據表裏的另外一個方式是從一個文檔裏把它們直接讀出來。文檔內容能夠是一些新行添加的INSERT語句。也就是上面提到過的運行SQL腳本的方法:

$ mysql-example sampdb < insert_president.sql;

或者在mysql命令行下:

$ source insert_president.sql ;

上面兩條語句都是基於文檔裏的內容是新加記錄的INSERT語句,若是文檔中的記錄並非以INSERT語句的形式寫在文擋中,而是以純數據值的形式來存放的,咱們這時能夠用Load DATA語句或mysqlimport工具來加載它們,例如:

mysql > LOAD DATA LOCAL INFILE 'member.txt' INTO TABLE member;

假設數據就是保存在member.txt文檔中,上面的語句將讀這個文件並把它的內容發送到服務器以加載到member數據表。

上面的LOAD DATA 語句還有一點須要注意,在默認狀況下,LOAD DATA 語句將默認各數據列的值以製表符分隔,各數據行以製表符分隔,數據值的排列順序與各數據列在數據表裏的前後順序一致。若是不使用默認的製表符做爲txt文件的分隔符,則須要指定文件記錄的分隔格式,要用到fields關鍵字。例如:

LOAD DATA INFILE 'member.txt' INTO TABLE member FIELDS TERMINATED BY ';'  ;

上面這條語句給出瞭如何加載以;做爲分隔符的數據文件。


檢索信息

SELECT語句容許以你喜歡的方式檢索和顯示數據表裏的信息。一般SELECT語句由如下幾個部分組成:

SELECT what to retrieve
FORM table or tables
WHERE conditions that data must satisfy;

在寫SELECT語句時,儘可能把你想檢索的東西描述清楚,再把可選子句寫出來。(FROM和WHERE就是比較常見的兩個子句),其餘子句包括GROUP BY、ORDER BY和LIMIT等。 有趣的是,SQL語句對書寫格式的要求並無Shell或大多數編程語言那麼嚴格,因此你在書寫SELECT語句時,選擇換行符的位置以及大小寫的要求時徹底能夠按照你的我的習慣來書寫,可是良好的書寫習慣會使SQL語句的閱讀性和後期的數據庫維護更便捷。

FROM子句通常不能省略(你要指定從哪一個數據表檢索數據),但SELECT 當操做不涉及數據表時,徹底沒有必要把FROM子句寫出來,例如:

mysql>    SECLECT 2+2,    'Hello, World!',    VERSION();

MySQL容許把表達式的計算結果當作輸出列的值,而不引用數據表。可是,當你明確須要使用哪一個數據表檢索數據時,應該用FROM子句指定數據表,固然還須要把想要查看的數據列的名字列舉出來。例如:

mysql>    SELECT * FROM student;

上面這條查詢將把student數據表的全部數據列所有顯示出來。(固然,檢索時應儘可能避免 * 的使用)想要查詢某一列的數據時,在SELECT後把數據列的名字逐個列出來就行,多個數據列之間用逗號隔開。例如:

mysql>    SELECT name, student_id FROM student;

上面提到過SQL語句對於大小寫並無嚴格的要求,可是須要注意的是,數據表的名字和數據庫的名字可能須要區分大小寫。(好比,在Linux系統上數據表和數據庫的名字是嚴格區分大小寫的)

指定檢索條件

想要完成更爲精確的查詢,須要給SELECT語句加上一個WHERE子句來篩選你想要的數據。例如:

mysql>    SELECT * FROM score WHERE score > 95;

或者匹配某一特定行的記錄:

mysql>    SELECT name, city FROM student WHERE student_id = '2017011111' ;

WHERE子句裏的表達式容許使用算術運算符、比較運算符和邏輯運算符,你能夠靈活的使用常數、數據表的數據列和函數調用進行運算。例如:

mysql>    SELECT name, birth , city, score FROM student 
        ->    WHERE birth < '1999-10-10' AND city IN('長春‘  ,  '吉林') ;

上面的這條查詢的意思是,從student表中找出家在長春或者吉林而且出生日期早於1999年10月10日的同窗,並把他們的姓名、生日、籍貫、分數列出來。在這條查詢中,用IN()操 做符來查找幾個值中的某一個會很方便。

NULL 值

NULl值是一個很特殊的值。它的含義是缺省(無數據或者未知數據),因此不能用它與「有數據」的值進行運算或者比較。若是須要對NULL值進行查找,就必須使用IS NULL 或IS NOT NULL 來判斷。例如:在一張記錄學生成績的表中把缺考的學生找出來:

mysql>    SELECT name, student_id, score FROM student_exam 
        ->    WHERE score IS NUll;

固然使用MySQL專用的比較操做符 <=> 也能完成NULL值與NULL 值之間的比較。上面的查詢能夠改成:

mysql>    SELECT name, student_id, score FROM student_exam
        ->    WHERE NOT( score <=> NULL);
須要注意的是,NULL值與0或者空字符串 並不相等。

對查詢結果進行排序

雖然數據記錄在查詢結果中的前後順序一般與他們在當初被插入時的前後順序一致。但若是數據表一旦通過增刪改查等一些操做後,這些操做每每會改變數據行在服務器所返回的數據表檢索結果中的前後順序。因此,除非你可以保證從服務器返回的數據事先沒有通過任何變更。不然,想讓查詢結果返回你但願的前後順序顯示,就必須給查詢命令增長一條ORDER BY 子句。例如:

mysql>    SELECT name, student_id, sex, score FROM 
        ->    student ORDER BY score;

ORDER BY子句默認的排序方式是升序(ASC),在ORDER BY 子句中的數據列名字後面加上DESC則表示按降序排列。也能夠對查詢結果的多個數據列進行排序,而每個數據列又均可以互不影響地分別按升序或降序進行排列。例如:

mysql>    SELECT name, student_id, score, sex, city 
        ->    FROM student ORDER BY score DESC, student_id ASC;
對於包含NULL的數據行,若是設定按升序排列,他們將出如今查詢的開頭;若是設定按降序排列,他們將出如今查詢結果的末尾。

限制查詢結果中的數據行個數

查詢結果每每由不少數據行構成,若是你只想要其中一小部分,能夠可查詢命令增長一個LIMIT子句。ORDER BY 配合LIMIT 1列出查詢中的排在第一行的那條結果。固然,你也能夠指定從查詢結果中抽出一部分,此時必須指定兩個值,第一個值給出要在查詢結果的開頭部分跳過的數據記錄個數,第二個值則是須要返回的數據記錄個數。例如:

mysql>    SELECT name, student_id, score 
        ->    FROM student ORDER BY score DESC LIMIT 10, 5;

上面這條查詢返回成績排在11到15名的同窗的信息。

對輸出列進行求值和命名

前面提到過MySQL容許把表達式的結果當作輸出列的值,而不引用數據表。數據表裏的數據列名字也能夠用在表達式裏,例如:

mysql>    SELECT CONCAT(student_id,' ', name) as stuinfo, CONCAT(city, ',' ,state) 
        ->    FROM student;

在上面的查詢中, 咱們對輸出咧的格式進行了設置:把學生的學號和姓名合起來顯示(以空格分隔),城市和省份也合起來輸出(以逗號分隔),而且在輸出結果中分別以別名顯示這兩列的標題。在爲數據列提供別名時,關鍵字AS能夠省略,可是若是省略它稍不留神可能會出現錯誤,例如:

mysql>    SELECT name city FROM student;

上面的查詢本意是查詢學生的姓名和籍貫,可是漏了name和city數據列之間的逗號,因而city將被視爲name的別名從而成爲了輸出列的表頭。

與日期相關的問題

MySQL中常見的有關日期的操做,有下面幾種:

  • 按日期排序
  • 查找某個日期或者某個日期範圍
  • 提取日期中的年、月、日等組成部分
  • 計算兩個日期之間的時間距離
  • 用一個日期加上或減去一個時間間隔以求出另外一個日期
# 1.
mysql>    SELECT * FROM student WHERE date = '2018-10-10' ;

# 2. 
mysql>    SELECT * FROM student WHERE date >= '2018-10-01' AND date < ' 2018-10-13' ;

# 3.  日期中的年、 月、 日能夠用函數 YEAR() 、 MONTH()、 DAYOFMONTH() 分別提取出來。
mysql>    SELECT * FROM student WHERE MONTH(birth) = 3;  # 把生日在3月的同窗列出來,也能夠用MONTHNAME(birth) = 'March'

#4. 生日在同一天的同窗,不必定同年。(因此能夠用DAYOFMONTH)
mysql>    SELECT * FROM student WHERE MONTH(birth) = 3 AND DAYOFMONTH(birth) = 29;

#5. 
mysql>    SELECT name, city, TIMESTAMPDIFF(YEAR, birth,CURDATE()) as age FROM student 
        ->    WHERE birth IS NOT NULL  ORDER BY age DESC LIMIT 1;

模式匹配

MySQL支持模式匹配操做,這使得咱們可以在沒有給出精確比較值的狀況下把有關的數據行檢索出來,模式匹配用(LIKE和NOT LIKE 操做符),還須要你提供一個包含通配符的字符串。_只能匹配一個字符, % 能匹配零到任意字符序列。例如:

mysql>    SELECT name, city, student_id FROM student WHERE student_id LIKE '1%' ;

mysql>    SELECT name, city , student_id FROM WHERE city LIKE '__';

MySQL還提供基於正則表達式和REGEXP操做符的另外一種更爲靈活和強大的匹配形式。例如:

mysql>    SELECT name, city , student_id, sex FROM WHERE city REGEXP '^吉’ ;
# 把籍貫以吉開頭的同窗的信息列出來
# 更多關於正則表達是的知識,能夠參考我關於正則表達是的筆記

設置和使用SQL變量

MySQL容許自定義變量。咱們可使用查詢結果來設置變量,這使咱們可以方便地把一些值保存起來以供從此查詢。

mysql>    SELECT @score := score FROM student WHERE score = 60 ;

mysql>    SELECT name, student_id , score FROM student 
        ->    WHERE score > @score ORDER BY score DESC;

變量額命名語法是「@變量名」 ,賦值語法是在SELECT語句裏使用一個「@變量名:= 值」 形式的表達式。其實上面的查詢能夠經過一個聯結或子查詢語句獲得,稍後咱們會看到。 SET語句也能用來對變量賦值。

mysql>    SET @today := CURDATE() ;

生成計數信息

MySQL最有用的功能之一是它可以依據大量未經加工的數據生成多種統計彙總信息。找出一組數據裏到底有多少種不一樣的取值是一項比較常見的統計工做,而關鍵字DISTINCT剛好能讓咱們把在查詢結果中重複出現的數據行清除掉。例如:

mysql>    SELECT DISTINCT city FROM student ORDER BY city;

上面的查詢把學生籍貫不加劇復的列舉出來。另外一個比較常見的統計工做是利用COUNT() 函數來計數。COUNT(*)能把你的查詢到底選取了多少數據行作一個統計。例如:

mysql>    SELECT COUNT(*) FROM student WHERE score <60 ;

上面的查詢返回成績不及格的同窗的人數。COUNT(*)的統計結果是被選中的數據行的總數,而COUNT(數據列名稱)值則只統計全體非NULL值的個數。COUNT()能夠和DISTINCT連用,用以統計有多少不一樣的非NULL值。例如:

mysql>    SELECT COUNT(DISTINCT city) FROM student;

上面的查詢能夠統計出學生數據表中到底有多少不一樣的城市個數。COUNT()函數和WHERE子句連用,能夠篩選出不一樣類型的個數。例如:

mysql>    SELECT COUNT(*) FROM student WHERE sex = 'F';
mysql>    SELECT COUNT(*) FROM student WHERE sex = 'M';

事實上上面的查詢能夠用更爲方便的GROUP BY子句進行分類,MySQL能夠只用一個查詢就把某數據列裏的不一樣值分別出現過多少次的狀況統計出來。上面的例子能夠作以下修改,例如:

mysql>    SELECT sex, COUNT(*) AS 人數 FROM student GROUP BY sex ;

若是須要進行這種分門別類的統計,GROUP BY子句是必不可少的選擇,它的做用是讓MySQL知道在統計以前應該如何對有關的數據記錄分類。與反覆使用多個彼此近似的查詢來分別統計某數據列不一樣取值出現次數的作法相比,把COUNT(*)函數與GROUP BY子句相結合的作法有不少有點:

  • 在開始統計以前,咱們沒必要知道將被統計的數據列不一樣取值出現次數到底有多少種不一樣的取值
  • 咱們只須要使用一個而不是好幾個查詢
  • 由於只用一個查詢就能把全部的結果都查出來,因此咱們還能對輸出進行排序

前兩個優勢有助於簡化查詢語句的書寫,而第三個優勢它能讓咱們更加靈活地顯示查詢結果。例如:

mysql>    SELECT city, COUNT(*) AS 人數 FROM student GROUP BY city ORDER  BY 人數 DESC;

上面的查詢把學生表中分別來自什麼城市作一個分類,統計數量後按降序排序。(來自哪一個地方的學生最多) 若是你打算用ORDER BY 子句對一個計算出來的結果進行歸類,可使用輸出列的別名或者它們在查詢結果裏的出現位置來設定(不推薦,也不屬於標準SQL的一部分)。例如:

mysql>    SELECT MONTH(birth) AS Month, MONTHNAME(birth) AS name, COUNT(*) AS 人數 
        ->    FROM student GROUP BY name ORDER BY Month;

一樣,COUNT()函數還能與ORDER BY 和LIMIT子句聯合使用。而想要把與某個特定COUNT()值相對應的記錄找出來,須要使用HAVING子句。(WHERE和HAVING,簡單地能夠理解爲一個在分組前篩選數據[WHERE],一個在分組後篩選數據[HAVING],WHERE後面不能跟聚合函數)例如:

mysql>    SELECT city, COUNT(*) AS 人數 FROM student GROUP city HAVING 人數 > 2 ORDER BY 人數 DESC;

除COUNT()之外,MySQL還有其餘一些彙總函數。(MIN()、MAX()、SUM()和AVG()..) 要讓MySQL對數據行分組統計結果作進一步的統計獲得所謂的 「超級聚合」 值。加上WITH ROLLUP 子句便可。例如:

mysql>    SELECT sex, COUNT(*) FROM student GROUP BY sex WITH ROLLUP;

上面這條查詢將對兩種性別的學生人數進行彙總並生成一行輸出。


多表查詢

當你打算從多個數據表選取信息時,有一種方法叫作聯結(join)。把一個數據表與另外一個數據表中的信息結合起來才能獲得查詢結果。聯結操做是經過並把兩個(或多個)數據表裏的同類數據進行匹配而完成的。多表操做的另外一種方法是將SELECT語句嵌套在另外一個SELECT語句裏,前者叫作子查詢。例如:

mysql>    SELECT student.name,grade_event.date, score.score, grade_event.category 
        ->    FROM grade_event INNER JOIN score INNER JOIN student 
        ->    ON grade_event.event_id = score.event_id 
        ->    AND score.student_id = student.student_id
        ->    WHERE grade_event.date = '2018-10-07' ;

這條查詢先查出給定日期的grade_event行,再利用此行裏的event_id 把score數據表裏擁有同一event_id 的考試分數都查出來,而且把score和student數據表裏都有student_id的數據列查出來,利用這個關係把學號映射爲他們的姓名。每找到一組彼此都匹配的grade_event行和score行,score行和student行,就把學生的姓名、考試分數、日期和考試事件的類型顯示出來。這條查詢與單表查詢相比:

  • 在FROM子句裏,咱們列舉出了多個數據表的名字,由於咱們要從多個數據表裏檢索數據
  • 在ON子句裏,咱們給出了grade_event數據表和score數據表,score數據表和student數據表的聯結條件,這grade_event和score數據表裏的event_id 列的值必須相互匹配(而且 爲了消除歧義,這裏對event_id進行了徹底限定),而score和student數據表裏的student_id列的值必須相互匹配。

換一種狀況,加入如今有一個表是記錄學生們的考試缺考狀況(absence表),若是你想看到缺考的學生信息,就須要把absence表與student表經過student_id 列的值聯結起來。例如:

mysql>    SELECT student.student_id, student.name,
        ->    COUNT(absence.date) AS absences
        ->    FROM student INNER JOIN absence 
        ->    ON student.student_id = absence.student_id
        ->    GROUP BY student.student_id;

上面的這條查詢對於想知道都有哪些學生缺考的狀況,查詢結果正是咱們須要的。但假如你須要對全部學生的考生出勤狀況作一個統計,(即須要同時顯示出沒有缺考的學生信息)那麼咱們就須要用LEFT JOIN來代替普通的聯結操做。 LEFT JOIN 將使MySQL 爲聯結操做中第一個數據表(即關鍵字LEFT JOIN左邊的數據表)裏的每個中選數據行生成一個輸出行。上例能夠修改成:

mysql>    SELECT student.student_id, student.name,
        ->    COUNT(absence.date) AS absences
        ->    FROM student LEFT JOIN absence
        ->    ON student.student_id = absence.student_id 
        ->    GROUP BY student.student_id;

上面這條查詢,不只能夠列出缺考的學生的信息,還會返回沒有缺考的學生的信息,而且缺考次數統計爲0 。

RIGHT OUTER JOIN ....ON 即爲右聯結,與左聯結正好相反,用法相同。其實對左聯結來講,將表的順序交換就是右聯結。還有全聯結(全外聯結),但MySQL不支持此種聯結方式。

聯結操做並不是只能做用於不一樣的數據表,你能夠把某個數據表和它自身結合起來。例如:你想知道在student表中是否有兩個同窗籍貫相同。

mysql>    SELECT s1.name, s1.city, s1.state FROM student AS s1 INNER JOIN student AS s2 
        ->    ON s1.city = s2.city AND s1.state =s2.state 
        ->    WHERE (s1.name != s2.name)
        ->    ORDER BY state, city , name;

這條查詢有兩個須要注意的地方:

  • 它須要兩次用到同一個表,因此咱們必須爲它建立兩個別名(s1 和s2)才能把表中的同名數據列區分開來。
  • 用WHERE子句來確保每名學生的記錄只能與其餘學生相匹配,來剔除「記錄與它自己相匹配」的狀況。
MySQL認爲任何一個查詢都是一次「關聯」 ,並不只僅是一個查詢須要兩個表匹配才叫關聯,因此在MySQL中,每個查詢,每個片斷(包括子查詢,甚至是基於單表查 詢)均可以是一次關聯。MySQL執行關聯的策略很簡單:MySQL對任何關聯都執行嵌套循環關聯操做。即MySQL先在一個表中循環取出單條數據,而後在嵌套循環到下一個表中尋找匹配的行,依次下去,直到找到全部表中的匹配行爲止。而後根據各個表匹配的行,返回查詢須要的各個列。

多表檢索的另外一類方法,嵌套查詢

嵌套查詢也就是它一條SELECT語句嵌套在另外一條裏。例如:

mysql>    SELECT * FROM student WHERE student_id
        ->    NOT IN(SELECT student_id FROM absence);

上面的這條查詢把全體沒有缺勤的學生找出來。嵌套與內層的SELECT語句用來生成一個absence數據表裏出現過的student_id 值的集合,外層的SELECT語句負責把與該機合理的任何一個ID值都不匹配的student數據行檢索出來(NOT IN)。


END

相關文章
相關標籤/搜索