MySQL:數(shù)據(jù)操作、單表、多表查詢

數(shù)據(jù)操作

本節(jié)重點(diǎn)

單表查詢的語法

關(guān)鍵字的執(zhí)行優(yōu)先級(重點(diǎn))

簡單查詢

WHERE約束

分組查詢:GROUP BY

HAVING過濾

查詢排序:ORDER BY

限制查詢的記錄數(shù):LIMIT

使用正則表達(dá)式查詢

一.介紹

MySQL數(shù)據(jù)操作: DML

========================================================

在MySQL管理軟件中,可以通過SQL語句中的DML語言來實(shí)現(xiàn)數(shù)據(jù)的操作,包括

  1. 使用INSERT實(shí)現(xiàn)數(shù)據(jù)的插入
  2. UPDATE實(shí)現(xiàn)數(shù)據(jù)的更新
  3. 使用DELETE實(shí)現(xiàn)數(shù)據(jù)的刪除
  4. 使用SELECT查詢數(shù)據(jù)以及。

========================================================

內(nèi)容包括:

插入數(shù)據(jù)
更新數(shù)據(jù)
刪除數(shù)據(jù)
查詢數(shù)據(jù)

二.插入數(shù)據(jù)insert

1. 插入完整數(shù)據(jù)(順序插入)
    語法一:
    INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n);

    語法二:
    INSERT INTO 表名 VALUES (值1,值2,值3…值n);

2. 指定字段插入數(shù)據(jù)
    語法:
    INSERT INTO 表名(字段1,字段2,字段3…) VALUES (值1,值2,值3…);

3. 插入多條記錄
    語法:
    INSERT INTO 表名 VALUES
        (值1,值2,值3…值n),
        (值1,值2,值3…值n),
        (值1,值2,值3…值n);

4. 插入查詢結(jié)果
    語法:
    INSERT INTO 表名(字段1,字段2,字段3…字段n) 
                    SELECT (字段1,字段2,字段3…字段n) FROM 表2
                    WHERE …;

三 更新數(shù)據(jù)UPDATE

語法:
    UPDATE 表名 SET
        字段1=值1,
        字段2=值2,
        WHERE CONDITION;

示例:
    UPDATE mysql.user SET password=password(‘123’) 
        where user=’root’ and host=’localhost’;

四 刪除數(shù)據(jù)DELETE

語法:
    DELETE FROM 表名 
        WHERE CONITION;

示例:
    DELETE FROM mysql.user 
        WHERE password=’’;

練習(xí):
    更新MySQL root用戶密碼為mysql123
    刪除除從本地登錄的root用戶以外的所有用戶

權(quán)限管理

image.png
#授權(quán)表
user #該表放行的權(quán)限,針對:所有數(shù)據(jù),所有庫下所有表,以及表下的所有字段
db #該表放行的權(quán)限,針對:某一數(shù)據(jù)庫,該數(shù)據(jù)庫下的所有表,以及表下的所有字段
tables_priv #該表放行的權(quán)限。針對:某一張表,以及該表下的所有字段
columns_priv #該表放行的權(quán)限,針對:某一個(gè)字段

#按圖解釋:
user:放行db1,db2及其包含的所有
db:放行db1,及其db1包含的所有
tables_priv:放行db1.table1,及其該表包含的所有
columns_prive:放行db1.table1.column1,只放行該字段

- 創(chuàng)建賬號
  - 本地賬號
  - create user "dc"@"localhost" identified by "123";  #mysql -udc -p123
  - 從遠(yuǎn)程賬號
  - create user "dc"@"192.168.1.10" identified by "123"; # mysql -udc -p123 -h 服務(wù)端IP
  - create user "dc"@"192.168.1.%" identified by "123"; # 192.168.1.x 網(wǎng)段都可以訪問
  - create user "dc"@"%" identified by "123"; # mysql -udc -p123 -h 服務(wù)端IP # 所有網(wǎng)段都可以訪問服務(wù)端
- 授權(quán)
  - 級別從上到下
  - user:*.*
  - db:db1.*
  - tables_priv:db1.t1
  - columns_priv:id,name
- 例子
  - grant all on *.* to "dc"@"%";
  - grant select on *.* to "dc"@"localhost";
  - revoke select on  *.* from "dc"@"localhost";

#創(chuàng)建用戶
create user 'egon'@'1.1.1.1' identified by '123';
create user 'egon'@'192.168.1.%' identified by '123';
create user 'egon'@'%' identified by '123';


#授權(quán):對文件夾,對文件,對文件某一字段的權(quán)限
查看幫助:help grant
常用權(quán)限有:select,update,alter,delete
all可以代表除了grant之外的所有權(quán)限

#針對所有庫的授權(quán):*.*
grant select on *.* to 'egon1'@'localhost' identified by '123'; #只在user表中可以查到egon1用戶的select權(quán)限被設(shè)置為Y

#針對某一數(shù)據(jù)庫:db1.*
grant select on db1.* to 'egon2'@'%' identified by '123'; #只在db表中可以查到egon2用戶的select權(quán)限被設(shè)置為Y

#針對某一個(gè)表:db1.t1
grant select on db1.t1 to 'egon3'@'%' identified by '123';  #只在tables_priv表中可以查到egon3用戶的select權(quán)限

#針對某一個(gè)字段:
mysql> select * from t3;
+------+-------+------+
| id   | name  | age  |
+------+-------+------+
|    1 | egon1 |   18 |
|    2 | egon2 |   19 |
|    3 | egon3 |   29 |
+------+-------+------+

grant select (id,name),update (age) on db1.t3 to 'egon4'@'localhost' identified by '123'; 
#可以在tables_priv和columns_priv中看到相應(yīng)的權(quán)限
mysql> select * from tables_priv where user='egon4'\G
*************************** 1. row ***************************
       Host: localhost
         Db: db1
       User: egon4
 Table_name: t3
    Grantor: root@localhost
  Timestamp: 0000-00-00 00:00:00
 Table_priv:
Column_priv: Select,Update
row in set (0.00 sec)

mysql> select * from columns_priv where user='egon4'\G
*************************** 1. row ***************************
       Host: localhost
         Db: db1
       User: egon4
 Table_name: t3
Column_name: id
  Timestamp: 0000-00-00 00:00:00
Column_priv: Select
*************************** 2. row ***************************
       Host: localhost
         Db: db1
       User: egon4
 Table_name: t3
Column_name: name
  Timestamp: 0000-00-00 00:00:00
Column_priv: Select
*************************** 3. row ***************************
       Host: localhost
         Db: db1
       User: egon4
 Table_name: t3
Column_name: age
  Timestamp: 0000-00-00 00:00:00
Column_priv: Update
rows in set (0.00 sec)

#刪除權(quán)限
revoke select on db1.* to 'alex'@'%';

權(quán)限相關(guān)操作

單表查詢

單表查詢的語法

關(guān)鍵字的執(zhí)行優(yōu)先級(重點(diǎn))

簡單查詢

WHERE約束

分組查詢:GROUP BY

HAVING過濾

查詢排序:ORDER BY

限制查詢的記錄數(shù):LIMIT

使用正則表達(dá)式查詢

一 單表查詢的語法

SELECT 字段1,字段2... FROM 表名
                  WHERE 條件
                  GROUP BY field
                  HAVING 篩選
                  ORDER BY field
                  LIMIT 限制條數(shù)

二 關(guān)鍵字的執(zhí)行優(yōu)先級(重點(diǎn))

重點(diǎn)中的重點(diǎn):關(guān)鍵字的執(zhí)行優(yōu)先級
from
where
group by
having
select
distinct
order by
limit

1.找到表:from

2.拿著where指定的約束條件,去文件/表中取出一條條記錄

3.將取出的一條條記錄進(jìn)行分組group by,如果沒有g(shù)roup by,則整體作為一組

4.將分組的結(jié)果進(jìn)行having過濾

5.執(zhí)行select

6.去重

7.將結(jié)果按條件排序:order by

8.限制結(jié)果的顯示條數(shù)

詳細(xì)見:http://www.cnblogs.com/linhaifeng/articles/7372774.html

三 簡單查詢

#簡單查詢
    SELECT id,name,sex,age,hire_date,post,post_comment,salary,office,depart_id 
    FROM employee;

    SELECT * FROM employee;

    SELECT name,salary FROM employee;

#避免重復(fù)DISTINCT
    SELECT DISTINCT post FROM employee;    

#通過四則運(yùn)算查詢
    SELECT name, salary*12 FROM employee;
    SELECT name, salary*12 AS Annual_salary FROM employee;
    SELECT name, salary*12 Annual_salary FROM employee;

#定義顯示格式
   CONCAT() 函數(shù)用于連接字符串
   SELECT CONCAT('姓名: ',name,'  年薪: ', salary*12)  AS Annual_salary 
   FROM employee;

   CONCAT_WS() 第一個(gè)參數(shù)為分隔符
   SELECT CONCAT_WS(':',name,salary*12)  AS Annual_salary 
   FROM employee;

mysql操作查詢結(jié)果case when then else end用法

Case具有兩種格式。簡單Case函數(shù)和Case搜索函數(shù)。

  • 簡單Case函數(shù)
CASE sex 
         WHEN '1' THEN '男' 
         WHEN '2' THEN '女' 
ELSE '其他' END 
  • Case搜索函數(shù)
CASE WHEN sex = '1' THEN '男' 
         WHEN sex = '2' THEN '女' 
ELSE '其他' END 

這兩種方式,可以實(shí)現(xiàn)相同的功能。簡單Case函數(shù)的寫法相對比較簡潔,但是和Case搜索函數(shù)相比,功能方面會有些限制,比如寫判斷式。

還有一個(gè)需要注意的問題,Case函數(shù)只返回第一個(gè)符合條件的值,剩下的Case部分將會被自動忽略。

--比如說,下面這段SQL,你永遠(yuǎn)無法得到“第二類”這個(gè)結(jié)果

CASE WHEN col_1 IN ( 'a', 'b') THEN '第一類' 
         WHEN col_1 IN ('a')       THEN '第二類' 
ELSE'其他' END 

下面我們來看一下,使用Case函數(shù)都能做些什么事情。

一,已知數(shù)據(jù)按照另外一種方式進(jìn)行分組,分析。

有如下數(shù)據(jù):

(為了看得更清楚,我并沒有使用國家代碼,而是直接用國家名作為Primary Key)

國家(country) 人口(population)
中國 600
美國 100
加拿大 100
英國 200
法國 300
日本 250
德國 200
墨西哥 50
印度 250

根據(jù)這個(gè)國家人口數(shù)據(jù),統(tǒng)計(jì)亞洲和北美洲的人口數(shù)量。應(yīng)該得到下面這個(gè)結(jié)果。
洲 人口
亞洲 1100
北美洲 250
其他 700
想要解決這個(gè)問題,你會怎么做?生成一個(gè)帶有洲Code的View,是一個(gè)解決方法,但是這樣很難動態(tài)的改變統(tǒng)計(jì)的方式。
如果使用Case函數(shù),SQL代碼如下:

SELECT  SUM(population), 
        CASE country 
                WHEN '中國'     THEN '亞洲' 
                WHEN '印度'     THEN '亞洲' 
                WHEN '日本'     THEN '亞洲' 
                WHEN '美國'     THEN '北美洲' 
                WHEN '加拿大'  THEN '北美洲' 
                WHEN '墨西哥'  THEN '北美洲' 
        ELSE '其他' END 
FROM    Table_A 
GROUP BY CASE country 
                WHEN '中國'     THEN '亞洲' 
                WHEN '印度'     THEN '亞洲' 
                WHEN '日本'     THEN '亞洲' 
                WHEN '美國'     THEN '北美洲' 
                WHEN '加拿大'  THEN '北美洲' 
                WHEN '墨西哥'  THEN '北美洲' 
        ELSE '其他' END; 
同樣的,我們也可以用這個(gè)方法來判斷工資的等級,并統(tǒng)計(jì)每一等級的人數(shù)。SQL代碼如下; 
SELECT 
        CASE WHEN salary <= 500 THEN '1' 
             WHEN salary > 500 AND salary <= 600  THEN '2' 
             WHEN salary > 600 AND salary <= 800  THEN '3' 
             WHEN salary > 800 AND salary <= 1000 THEN '4' 
        ELSE NULL END salary_class, 
        COUNT(*) 
FROM    Table_A 
GROUP BY 
        CASE WHEN salary <= 500 THEN '1' 
             WHEN salary > 500 AND salary <= 600  THEN '2' 
             WHEN salary > 600 AND salary <= 800  THEN '3' 
             WHEN salary > 800 AND salary <= 1000 THEN '4' 
        ELSE NULL END; 

二,用一個(gè)SQL語句完成不同條件的分組。

有如下數(shù)據(jù)
國家(country) 性別(sex) 人口(population)
中國 1 340
中國 2 260
美國 1 45
美國 2 55
加拿大 1 51
加拿大 2 49
英國 1 40
英國 2 60
按照國家和性別進(jìn)行分組,得出結(jié)果如下
國家 男 女
中國 340 260
美國 45 55
加拿大 51 49
英國 40 60
普通情況下,用UNION也可以實(shí)現(xiàn)用一條語句進(jìn)行查詢。但是那樣增加消耗(兩個(gè)Select部分),而且SQL語句會比較長。
下面是一個(gè)是用Case函數(shù)來完成這個(gè)功能的例子

SELECT country, 
       SUM( CASE WHEN sex = '1' THEN 
                      population ELSE 0 END),  --男性人口 
       SUM( CASE WHEN sex = '2' THEN 
                      population ELSE 0 END)   --女性人口 
FROM  Table_A 
GROUP BY country; 

這樣我們使用Select,完成對二維表的輸出形式,充分顯示了Case函數(shù)的強(qiáng)大。

三,在Check中使用Case函數(shù)。

在Check中使用Case函數(shù)在很多情況下都是非常不錯(cuò)的解決方法??赡苡泻芏嗳烁揪筒挥肅heck,那么我建議你在看過下面的例子之后也嘗試一下在SQL中使用Check。

下面我們來舉個(gè)例子 
公司A,這個(gè)公司有個(gè)規(guī)定,女職員的工資必須高于1000塊。如果用Check和Case來表現(xiàn)的話,如下所示 
CONSTRAINT check_salary CHECK 
           ( CASE WHEN sex = '2' 
                  THEN CASE WHEN salary > 1000 
                        THEN 1 ELSE 0 END 
                  ELSE 1 END = 1 ) 
如果單純使用Check,如下所示 
CONSTRAINT check_salary CHECK 
           ( sex = '2' AND salary > 1000 ) 
女職員的條件倒是符合了,男職員就無法輸入了

四,根據(jù)條件有選擇的UPDATE。

例,有如下更新條件
工資5000以上的職員,工資減少10%
工資在2000到4600之間的職員,工資增加15%
很容易考慮的是選擇執(zhí)行兩次UPDATE語句,如下所示

--條件1 
UPDATE Personnel 
SET salary = salary * 0.9 
WHERE salary >= 5000; 
--條件2 
UPDATE Personnel 
SET salary = salary * 1.15 
WHERE salary >= 2000 AND salary < 4600; 

但是事情沒有想象得那么簡單,假設(shè)有個(gè)人工資5000塊。首先,按照條件1,工資減少10%,變成工資4500。接下來運(yùn)行第二個(gè)SQL時(shí)候,因?yàn)檫@個(gè)人的工資是4500在2000到4600的范圍之內(nèi), 需增加15%,最后這個(gè)人的工資結(jié)果是5175,不但沒有減少,反而增加了。如果要是反過來執(zhí)行,那么工資4600的人相反會變成減少工資。暫且不管這個(gè)規(guī)章是多么荒誕,如果想要一個(gè)SQL 語句實(shí)現(xiàn)這個(gè)功能的話,我們需要用到Case函數(shù)。代碼如下:

UPDATE Personnel 
SET salary = CASE WHEN salary >= 5000 
             THEN salary * 0.9 
WHEN salary >= 2000 AND salary < 4600 
THEN salary * 1.15 
ELSE salary END; 

這里要注意一點(diǎn),最后一行的ELSE salary是必需的,要是沒有這行,不符合這兩個(gè)條件的人的工資將會被寫成NUll,那可就大事不妙了。在Case函數(shù)中Else部分的默認(rèn)值是NULL,這點(diǎn)是需要注意的地方。
這種方法還可以在很多地方使用,比如說變更主鍵這種累活。
一般情況下,要想把兩條數(shù)據(jù)的Primary key,a和b交換,需要經(jīng)過臨時(shí)存儲,拷貝,讀回?cái)?shù)據(jù)的三個(gè)過程,要是使用Case函數(shù)的話,一切都變得簡單多了。
p_key col_1 col_2
a 1 張三
b 2 李四
c 3 王五
假設(shè)有如上數(shù)據(jù),需要把主鍵a和b相互交換。用Case函數(shù)來實(shí)現(xiàn)的話,代碼如下

UPDATE SomeTable 
SET p_key = CASE WHEN p_key = 'a' 
THEN 'b' 
WHEN p_key = 'b' 
THEN 'a' 
ELSE p_key END 
WHERE p_key IN ('a', 'b'); 

同樣的也可以交換兩個(gè)Unique key。需要注意的是,如果有需要交換主鍵的情況發(fā)生,多半是當(dāng)初對這個(gè)表的設(shè)計(jì)進(jìn)行得不夠到位,建議檢查表的設(shè)計(jì)是否妥當(dāng)。

五,兩個(gè)表數(shù)據(jù)是否一致的檢查。

Case函數(shù)不同于DECODE函數(shù)。在Case函數(shù)中,可以使用BETWEEN,LIKE,IS NULL,IN,EXISTS等等。比如說使用IN,EXISTS,可以進(jìn)行子查詢,從而 實(shí)現(xiàn)更多的功能。

下面具個(gè)例子來說明,有兩個(gè)表,tbl_A,tbl_B,兩個(gè)表中都有keyCol列。現(xiàn)在我們對兩個(gè)表進(jìn)行比較,tbl_A中的keyCol列的數(shù)據(jù)如果在tbl_B的keyCol列的數(shù)據(jù)中可以找到, 返回結(jié)果'Matched',如果沒有找到,返回結(jié)果'Unmatched'。 
要實(shí)現(xiàn)下面這個(gè)功能,可以使用下面兩條語句 
--使用IN的時(shí)候 
SELECT keyCol, 
CASE WHEN keyCol IN ( SELECT keyCol FROM tbl_B ) 
THEN 'Matched' 
ELSE 'Unmatched' END Label 
FROM tbl_A; 
--使用EXISTS的時(shí)候 
SELECT keyCol, 
CASE WHEN EXISTS ( SELECT * FROM tbl_B 
WHERE tbl_A.keyCol = tbl_B.keyCol ) 
THEN 'Matched' 
ELSE 'Unmatched' END Label 
FROM tbl_A; 
使用IN和EXISTS的結(jié)果是相同的。也可以使用NOT IN和NOT EXISTS,但是這個(gè)時(shí)候要注意NULL的情況。 

六,在Case函數(shù)中使用合計(jì)函數(shù)

假設(shè)有下面一個(gè)表
學(xué)號(std_id) 課程ID(class_id) 課程名(class_name) 主修flag(main_class_flg)
100 1 經(jīng)濟(jì)學(xué) Y
100 2 歷史學(xué) N
200 2 歷史學(xué) N
200 3 考古學(xué) Y
200 4 計(jì)算機(jī) N
300 4 計(jì)算機(jī) N
400 5 化學(xué) N
500 6 數(shù)學(xué) N
有的學(xué)生選擇了同時(shí)修幾門課程(100,200)也有的學(xué)生只選擇了一門課程(300,400,500)。選修多門課程的學(xué)生,要選擇一門課程作為主修,主修flag里面寫入 Y。只選擇一門課程的學(xué)生,主修flag為N(實(shí)際上要是寫入Y的話,就沒有下面的麻煩事了,為了舉例子,還請多多包含)。
現(xiàn)在我們要按照下面兩個(gè)條件對這個(gè)表進(jìn)行查詢
只選修一門課程的人,返回那門課程的ID
選修多門課程的人,返回所選的主課程ID
簡單的想法就是,執(zhí)行兩條不同的SQL語句進(jìn)行查詢。

條件1 
--條件1:只選擇了一門課程的學(xué)生 
SELECT std_id, MAX(class_id) AS main_class 
FROM Studentclass 
GROUP BY std_id 
HAVING COUNT(*) = 1; 
執(zhí)行結(jié)果1 
STD_ID   MAIN_class 

---

300      4 
400      5 
500      6 
條件2 
--條件2:選擇多門課程的學(xué)生 
SELECT std_id, class_id AS main_class 
FROM Studentclass 
WHERE main_class_flg = 'Y' ; 
執(zhí)行結(jié)果2 
STD_ID  MAIN_class 

---

100     1 
200     3 
如果使用Case函數(shù),我們只要一條SQL語句就可以解決問題,具體如下所示 
SELECT  std_id, 
CASE WHEN COUNT(*) = 1  --只選擇一門課程的學(xué)生的情況 
THEN MAX(class_id) 
ELSE MAX(CASE WHEN main_class_flg = 'Y' 
THEN class_id 
ELSE NULL END 
) 
END AS main_class 
FROM Studentclass 
GROUP BY std_id; 
運(yùn)行結(jié)果 
STD_ID   MAIN_class 

---

100      1 
200      3 
300      4 
400      5 
500      6 
通過在Case函數(shù)中嵌套Case函數(shù),在合計(jì)函數(shù)中使用Case函數(shù)等方法,我們可以輕松的解決這個(gè)問題。使用Case函數(shù)給我們帶來了更大的自由度。 
最后提醒一下使用Case函數(shù)的新手注意不要犯下面的錯(cuò)誤 
CASE col_1 
WHEN 1        THEN 'Right' 
WHEN NULL  THEN 'Wrong' 
END 
在這個(gè)語句中When Null這一行總是返回unknown,所以永遠(yuǎn)不會出現(xiàn)Wrong的情況。因?yàn)檫@句可以替換成WHEN col_1 = NULL,這是一個(gè)錯(cuò)誤的用法,這個(gè)時(shí)候我們應(yīng)該選擇用WHEN col_1 IS NULL。

下面為您舉例說明了三種mysql中case when語句的使用方法,供參考學(xué)習(xí),如果對mysql中case when語句使用方面感興趣的話,不妨一看。

1。

1. select name,  
2. case   
3. when birthday<'1981' then 'old'  
4. when birthday>'1988' then 'yong'  
5. else 'ok' END YORN  
6. from lee; 

2。

1. select NAME,  
2. case name  
3. when 'sam' then 'yong'  
4. when 'lee' then 'handsome'  
5. else 'good' end  
6. from lee; 

當(dāng)然了case when語句還可以復(fù)合

3。

1. select name,birthday,  
2. case   
3. when birthday>'1983' then 'yong'  
4. when name='lee' then 'handsome'  
5. else 'just so so ' end  
6. from lee;  

以上就是mysql中case when語句的使用示例的介紹。

四 WHERE約束

where字句中可以使用:

  1. 比較運(yùn)算符:><>= <= <> !=
  2. between 80 and 100 值在10到20之間
  3. in(80,90,100) 值是10或20或30
  4. like 'egon%'
    pattern可以是%或_,
    %表示任意多字符
    _表示一個(gè)字符
  5. 邏輯運(yùn)算符:在多個(gè)條件直接可以使用邏輯運(yùn)算符 and or not
#1:單條件查詢
    SELECT name FROM employee
        WHERE post='sale';

#2:多條件查詢
    SELECT name,salary FROM employee
        WHERE post='teacher' AND salary>10000;

#3:關(guān)鍵字BETWEEN AND
    SELECT name,salary FROM employee 
        WHERE salary BETWEEN 10000 AND 20000;

    SELECT name,salary FROM employee 
        WHERE salary NOT BETWEEN 10000 AND 20000;

#4:關(guān)鍵字IS NULL(判斷某個(gè)字段是否為NULL不能用等號,需要用IS)
    SELECT name,post_comment FROM employee 
        WHERE post_comment IS NULL;

    SELECT name,post_comment FROM employee 
        WHERE post_comment IS NOT NULL;

    SELECT name,post_comment FROM employee 
        WHERE post_comment=''; 注意''是空字符串,不是null
    ps:
        執(zhí)行
        update employee set post_comment='' where id=2;
        再用上條查看,就會有結(jié)果了

#5:關(guān)鍵字IN集合查詢
    SELECT name,salary FROM employee 
        WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ;

    SELECT name,salary FROM employee 
        WHERE salary IN (3000,3500,4000,9000) ;

    SELECT name,salary FROM employee 
        WHERE salary NOT IN (3000,3500,4000,9000) ;

#6:關(guān)鍵字LIKE模糊查詢
    通配符’%’
    SELECT * FROM employee 
            WHERE name LIKE 'eg%';

    通配符’_’
    SELECT * FROM employee 
            WHERE name LIKE 'al__';

五 分組查詢:GROUP BY

一 什么是分組?為什么要分組?

#1、首先明確一點(diǎn):分組發(fā)生在where之后,即分組是基于where之后得到的記錄而進(jìn)行的

#2、分組指的是:將所有記錄按照某個(gè)相同字段進(jìn)行歸類,比如針對員工信息表的職位分組,或者按照性別進(jìn)行分組等

#3、為何要分組呢?
    取每個(gè)部門的最高工資
    取每個(gè)部門的員工數(shù)
    取男人數(shù)和女人數(shù)

小竅門:‘每’這個(gè)字后面的字段,就是我們分組的依據(jù)


#4、大前提:
    可以按照任意字段分組,但是分組完畢后,比如group by post,只能查看post字段,如果想查看組內(nèi)信息,需要借助于聚合函數(shù)

二 ONLY_FULL_GROUP_BY

#查看MySQL 5.7默認(rèn)的sql_mode如下:
mysql> select @@global.sql_mode;
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

#?。?!注意
ONLY_FULL_GROUP_BY的語義就是確定select target list中的所有列的值都是明確語義,簡單的說來,在ONLY_FULL_GROUP_BY模式下,target list中的值要么是來自于聚集函數(shù)的結(jié)果,要么是來自于group by list中的表達(dá)式的值。


#設(shè)置sql_mole如下操作(我們可以去掉ONLY_FULL_GROUP_BY模式):
mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

!??!SQL_MODE設(shè)置!??!
mysql> select @@global.sql_mode;
+-------------------+
| @@global.sql_mode |
+-------------------+
|                   |
+-------------------+
row in set (0.00 sec)

mysql> select * from emp group by post; 
+----+------+--------+-----+------------+----------------------------+--------------+------------+--------+-----------+
| id | name | sex    | age | hire_date  | post                       | post_comment | salary     | office | depart_id |
+----+------+--------+-----+------------+----------------------------+--------------+------------+--------+-----------+
| 14 | 張野 | male   |  28 | 2016-03-11 | operation                  | NULL         |   10000.13 |    403 |         3 |
|  9 | 歪歪 | female |  48 | 2015-03-11 | sale                       | NULL         |    3000.13 |    402 |         2 |
|  2 | alex | male   |  78 | 2015-03-02 | teacher                    | NULL         | 1000000.31 |    401 |         1 |
|  1 | egon | male   |  18 | 2017-03-01 | 老男孩駐沙河辦事處外交大使 | NULL         |    7300.33 |    401 |         1 |
+----+------+--------+-----+------------+----------------------------+--------------+------------+--------+-----------+
rows in set (0.00 sec)


#由于沒有設(shè)置ONLY_FULL_GROUP_BY,于是也可以有結(jié)果,默認(rèn)都是組內(nèi)的第一條記錄,但其實(shí)這是沒有意義的

mysql> set global sql_mode='ONLY_FULL_GROUP_BY';
Query OK, 0 rows affected (0.00 sec)

mysql> quit #設(shè)置成功后,一定要退出,然后重新登錄方可生效
Bye

mysql> use db1;
Database changed
mysql> select * from emp group by post; #報(bào)錯(cuò)
ERROR 1055 (42000): 'db1.emp.id' isn't in GROUP BY
mysql> select post,count(id) from emp group by post; #只能查看分組依據(jù)和使用聚合函數(shù)
+----------------------------+-----------+
| post                       | count(id) |
+----------------------------+-----------+
| operation                  |         5 |
| sale                       |         5 |
| teacher                    |         7 |
| 老男孩駐沙河辦事處外交大使 |         1 |
+----------------------------+-----------+
rows in set (0.00 sec)

三 GROUP BY

單獨(dú)使用GROUP BY關(guān)鍵字分組
    SELECT post FROM employee GROUP BY post;
    注意:我們按照post字段分組,那么select查詢的字段只能是post,想要獲取組內(nèi)的其他相關(guān)信息,需要借助函數(shù)

GROUP BY關(guān)鍵字和GROUP_CONCAT()函數(shù)一起使用
    SELECT post,GROUP_CONCAT(name) FROM employee GROUP BY post;#按照崗位分組,并查看組內(nèi)成員名
    SELECT post,GROUP_CONCAT(name) as emp_members FROM employee GROUP BY post;

GROUP BY與聚合函數(shù)一起使用
    select post,count(id) as count from employee group by post;#按照崗位分組,并查看每個(gè)組有多少人

強(qiáng)調(diào):

如果我們用unique的字段作為分組的依據(jù),則每一條記錄自成一組,這種分組沒有意義
多條記錄之間的某個(gè)字段值相同,該字段通常用來作為分組的依據(jù)

四 聚合函數(shù)

#強(qiáng)調(diào):聚合函數(shù)聚合的是組的內(nèi)容,若是沒有分組,則默認(rèn)一組

示例:
    SELECT COUNT(*) FROM employee;
    SELECT COUNT(*) FROM employee WHERE depart_id=1;
    SELECT MAX(salary) FROM employee;
    SELECT MIN(salary) FROM employee;
    SELECT AVG(salary) FROM employee;
    SELECT SUM(salary) FROM employee;
    SELECT SUM(salary) FROM employee WHERE depart_id=3;

六 HAVING過濾

HAVING與WHERE不一樣的地方在于!!!!!!

#!??!執(zhí)行優(yōu)先級從高到低:where > group by > having 
#1. Where 發(fā)生在分組group by之前,因而Where中可以有任意字段,但是絕對不能使用聚合函數(shù)。

#2. Having發(fā)生在分組group by之后,因而Having中可以使用分組的字段,無法直接取到其他字段,可以使用聚合函數(shù)

與where最大的區(qū)別就是能夠使用聚合函數(shù)來過濾條件

七 查詢排序:ORDER BY

按單列排序
    SELECT * FROM employee ORDER BY salary;
    SELECT * FROM employee ORDER BY salary ASC;
    SELECT * FROM employee ORDER BY salary DESC;

按多列排序:先按照age排序,如果年紀(jì)相同,則按照薪資排序
    SELECT * from employee
        ORDER BY age,
        salary DESC;

八 限制查詢的記錄數(shù):LIMIT

示例:
    SELECT * FROM employee ORDER BY salary DESC 
        LIMIT 3;                    #默認(rèn)初始位置為0 

    SELECT * FROM employee ORDER BY salary DESC
        LIMIT 0,5; #從第0開始,即先查詢出第一條,然后包含這一條在內(nèi)往后查5條

    SELECT * FROM employee ORDER BY salary DESC
        LIMIT 5,5; #從第5開始,即先查詢出第6條,然后包含這一條在內(nèi)往后查5條

單獨(dú)使用limit來分頁顯示數(shù)據(jù)效率并不高

九 使用正則表達(dá)式查詢

SELECT * FROM employee WHERE name REGEXP '^ale';

SELECT * FROM employee WHERE name REGEXP 'on$';

SELECT * FROM employee WHERE name REGEXP 'm{2}';


小結(jié):對字符串匹配的方式
WHERE name = 'egon';
WHERE name LIKE 'yua%';
WHERE name REGEXP 'on$';

十 總結(jié)

  • 語法順序
    • select distinct 字段1,字段2,字段3 from 庫.表
    • where 條件
    • group by 分組條件
    • having 過濾
    • order by 排序字段(asc升序,desc降序)
    • limit n;
  • 執(zhí)行順序:
    • 先找表 from 庫.表
    • where 過濾掉不符合的數(shù)據(jù)
    • group by 分組
    • having by 過濾
    • distinct 去重
    • order by 排序
    • limit n 分頁
    • 打印select 字段......

多表查詢

一 介紹

本節(jié)主題

  • 多表連接查詢
  • 復(fù)合條件連接查詢
  • 子查詢

二 多表連接查詢

#重點(diǎn):外鏈接語法

SELECT 字段列表
    FROM 表1 INNER|LEFT|RIGHT JOIN 表2
    ON 表1.字段 = 表2.字段;

1 交叉連接:不適用任何匹配條件。生成笛卡爾積

mysql> select * from employee,department;

2 內(nèi)連接:只連接匹配的行

#找兩張表共有的部分,相當(dāng)于利用條件從笛卡爾積結(jié)果中篩選出了正確的結(jié)果
#department沒有204這個(gè)部門,因而employee表中關(guān)于204這條員工信息沒有匹配出來
mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee 
inner join department on employee.dep_id=department.id; 

3 外鏈接之左連接:優(yōu)先顯示左表全部記錄

#以左表為準(zhǔn),即找出所有員工信息,當(dāng)然包括沒有部門的員工
#本質(zhì)就是:在內(nèi)連接的基礎(chǔ)上增加左邊有右邊沒有的結(jié)果
mysql> select employee.id,employee.name,department.name as depart_name from employee 
left join department on employee.dep_id=department.id;

4 外鏈接之右連接:優(yōu)先顯示右表全部記錄

#以右表為準(zhǔn),即找出所有部門信息,包括沒有員工的部門
#本質(zhì)就是:在內(nèi)連接的基礎(chǔ)上增加右邊有左邊沒有的結(jié)果
mysql> select employee.id,employee.name,department.name as depart_name from employee right join department on employee.dep_id=department.id;

5 全外連接:顯示左右兩個(gè)表全部記錄

全外連接:在內(nèi)連接的基礎(chǔ)上增加左邊有右邊沒有的和右邊有左邊沒有的結(jié)果
#注意:mysql不支持全外連接 full JOIN
#強(qiáng)調(diào):mysql可以使用此種方式間接實(shí)現(xiàn)全外連接
select * from employee left join department on employee.dep_id = department.id
union
select * from employee right join department on employee.dep_id = department.id
;

三 符合條件連接查詢

#示例1:以內(nèi)連接的方式查詢employee和department表,并且employee表中的age字段值必須大于25,即找出年齡大于25歲的員工以及員工所在的部門
select employee.name,department.name from employee inner join department
    on employee.dep_id = department.id
    where age > 25;

#示例2:以內(nèi)連接的方式查詢employee和department表,并且以age字段的升序方式顯示
select employee.id,employee.name,employee.age,department.name from employee,department
    where employee.dep_id = department.id
    and age > 25
    order by age asc;

四 子查詢

#1:子查詢是將一個(gè)查詢語句嵌套在另一個(gè)查詢語句中。
#2:內(nèi)層查詢語句的查詢結(jié)果,可以為外層查詢語句提供查詢條件。
#3:子查詢中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等關(guān)鍵字
#4:還可以包含比較運(yùn)算符:= 、 !=、> 、<等

1 帶IN關(guān)鍵字的子查詢

#查詢平均年齡在25歲以上的部門名
select id,name from department
    where id in 
        (select dep_id from employee group by dep_id having avg(age) > 25);

#查看技術(shù)部員工姓名
select name from employee
    where dep_id in 
        (select id from department where name='技術(shù)');

#查看不足1人的部門名
select name from department
    where id in 
        (select dep_id from employee group by dep_id having count(id) <=1);

2 帶比較運(yùn)算符的子查詢

#比較運(yùn)算符:=、!=、>、>=、<、<=、<>
#查詢大于所有人平均年齡的員工名與年齡
mysql> select name,age from emp where age > (select avg(age) from emp);
+---------+------+
| name | age |
+---------+------+
| alex | 48 |
| wupeiqi | 38 |
+---------+------+
rows in set (0.00 sec)


#查詢大于部門內(nèi)平均年齡的員工名、年齡
select t1.name,t1.age from emp t1
inner join 
(select dep_id,avg(age) avg_age from emp group by dep_id) t2
on t1.dep_id = t2.dep_id
where t1.age > t2.avg_age;

3 帶EXISTS關(guān)鍵字的子查詢

EXISTS關(guān)字鍵字表示存在。在使用EXISTS關(guān)鍵字時(shí),內(nèi)層查詢語句不返回查詢的記錄。

而是返回一個(gè)真假值。True或False

當(dāng)返回True時(shí),外層查詢語句將進(jìn)行查詢;當(dāng)返回值為False時(shí),外層查詢語句不進(jìn)行查詢

#department表中存在dept_id=203,Ture
mysql> select * from employee
    ->     where exists
    ->         (select id from department where id=200);
+----+------------+--------+------+--------+
| id | name       | sex    | age  | dep_id |
+----+------------+--------+------+--------+
|  1 | egon       | male   |   18 |    200 |
|  2 | alex       | female |   48 |    201 |
|  3 | wupeiqi    | male   |   38 |    201 |
|  4 | yuanhao    | female |   28 |    202 |
|  5 | liwenzhou  | male   |   18 |    200 |
|  6 | jingliyang | female |   18 |    204 |
+----+------------+--------+------+--------+

#department表中存在dept_id=205,F(xiàn)alse
mysql> select * from employee
    ->     where exists
    ->         (select id from department where id=204);
Empty set (0.00 sec)

補(bǔ)充 一 SELECT語句關(guān)鍵字的定義順序

SELECT DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>

補(bǔ)充 二 SELECT語句關(guān)鍵字的執(zhí)行順序

(7)     SELECT 
(8)     DISTINCT <select_list>
(1)     FROM <left_table>
(3)     <join_type> JOIN <right_table>
(2)     ON <join_condition>
(4)     WHERE <where_condition>
(5)     GROUP BY <group_by_list>
(6)     HAVING <having_condition>
(9)     ORDER BY <order_by_condition>
(10)    LIMIT <limit_number>

五 綜合練習(xí)

init.sql文件內(nèi)容

/*
 數(shù)據(jù)導(dǎo)入:
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50624
 Source Host           : localhost
 Source Database       : sqlexam

 Target Server Type    : MySQL
 Target Server Version : 50624
 File Encoding         : utf-8

 Date: 10/21/2016 06:46:46 AM
*/

SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
--  Table structure for `class`
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `caption` varchar(32) NOT NULL,
  PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `class`
-- ----------------------------
BEGIN;
INSERT INTO `class` VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班');
COMMIT;

-- ----------------------------
--  Table structure for `course`
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(32) NOT NULL,
  `teacher_id` int(11) NOT NULL,
  PRIMARY KEY (`cid`),
  KEY `fk_course_teacher` (`teacher_id`),
  CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `course`
-- ----------------------------
BEGIN;
INSERT INTO `course` VALUES ('1', '生物', '1'), ('2', '物理', '2'), ('3', '體育', '3'), ('4', '美術(shù)', '2');
COMMIT;

-- ----------------------------
--  Table structure for `score`
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) NOT NULL,
  `course_id` int(11) NOT NULL,
  `num` int(11) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `fk_score_student` (`student_id`),
  KEY `fk_score_course` (`course_id`),
  CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`),
  CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `score`
-- ----------------------------
BEGIN;
INSERT INTO `score` VALUES ('1', '1', '1', '10'), ('2', '1', '2', '9'), ('5', '1', '4', '66'), ('6', '2', '1', '8'), ('8', '2', '3', '68'), ('9', '2', '4', '99'), ('10', '3', '1', '77'), ('11', '3', '2', '66'), ('12', '3', '3', '87'), ('13', '3', '4', '99'), ('14', '4', '1', '79'), ('15', '4', '2', '11'), ('16', '4', '3', '67'), ('17', '4', '4', '100'), ('18', '5', '1', '79'), ('19', '5', '2', '11'), ('20', '5', '3', '67'), ('21', '5', '4', '100'), ('22', '6', '1', '9'), ('23', '6', '2', '100'), ('24', '6', '3', '67'), ('25', '6', '4', '100'), ('26', '7', '1', '9'), ('27', '7', '2', '100'), ('28', '7', '3', '67'), ('29', '7', '4', '88'), ('30', '8', '1', '9'), ('31', '8', '2', '100'), ('32', '8', '3', '67'), ('33', '8', '4', '88'), ('34', '9', '1', '91'), ('35', '9', '2', '88'), ('36', '9', '3', '67'), ('37', '9', '4', '22'), ('38', '10', '1', '90'), ('39', '10', '2', '77'), ('40', '10', '3', '43'), ('41', '10', '4', '87'), ('42', '11', '1', '90'), ('43', '11', '2', '77'), ('44', '11', '3', '43'), ('45', '11', '4', '87'), ('46', '12', '1', '90'), ('47', '12', '2', '77'), ('48', '12', '3', '43'), ('49', '12', '4', '87'), ('52', '13', '3', '87');
COMMIT;

-- ----------------------------
--  Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `gender` char(1) NOT NULL,
  `class_id` int(11) NOT NULL,
  `sname` varchar(32) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `fk_class` (`class_id`),
  CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `student`
-- ----------------------------
BEGIN;
INSERT INTO `student` VALUES ('1', '男', '1', '理解'), ('2', '女', '1', '鋼蛋'), ('3', '男', '1', '張三'), ('4', '男', '1', '張一'), ('5', '女', '1', '張二'), ('6', '男', '1', '張四'), ('7', '女', '2', '鐵錘'), ('8', '男', '2', '李三'), ('9', '男', '2', '李一'), ('10', '女', '2', '李二'), ('11', '男', '2', '李四'), ('12', '女', '3', '如花'), ('13', '男', '3', '劉三'), ('14', '男', '3', '劉一'), ('15', '女', '3', '劉二'), ('16', '男', '3', '劉四');
COMMIT;

-- ----------------------------
--  Table structure for `teacher`
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `tid` int(11) NOT NULL AUTO_INCREMENT,
  `tname` varchar(32) NOT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `teacher`
-- ----------------------------
BEGIN;
INSERT INTO `teacher` VALUES ('1', '張磊老師'), ('2', '李平老師'), ('3', '劉海燕老師'), ('4', '朱云海老師'), ('5', '李杰老師');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

從init.sql文件中導(dǎo)入數(shù)據(jù)

#準(zhǔn)備表、記錄
mysql> create database db1;
mysql> use db1;
mysql> source /root/init.sql
1、查詢所有的課程的名稱以及對應(yīng)的任課老師姓名

2、查詢學(xué)生表中男女生各有多少人

3、查詢物理成績等于100的學(xué)生的姓名

4、查詢平均成績大于八十分的同學(xué)的姓名和平均成績

5、查詢所有學(xué)生的學(xué)號,姓名,選課數(shù),總成績

6、 查詢姓李老師的個(gè)數(shù)

7、 查詢沒有報(bào)李平老師課的學(xué)生姓名

8、 查詢物理課程比生物課程高的學(xué)生的學(xué)號

9、 查詢沒有同時(shí)選修物理課程和體育課程的學(xué)生姓名

10、查詢掛科超過兩門(包括兩門)的學(xué)生姓名和班級
、查詢選修了所有課程的學(xué)生姓名

12、查詢李平老師教的課程的所有成績記錄

13、查詢?nèi)繉W(xué)生都選修了的課程號和課程名

14、查詢每門課程被選修的次數(shù)

15、查詢之選修了一門課程的學(xué)生姓名和學(xué)號

16、查詢所有學(xué)生考出的成績并按從高到低排序(成績?nèi)ブ兀?
17、查詢平均成績大于85的學(xué)生姓名和平均成績

18、查詢生物成績不及格的學(xué)生姓名和對應(yīng)生物分?jǐn)?shù)

19、查詢在所有選修了李平老師課程的學(xué)生中,這些課程(李平老師的課程,不是所有課程)平均成績最高的學(xué)生姓名

20、查詢每門課程成績最好的前兩名學(xué)生姓名

21、查詢不同課程但成績相同的學(xué)號,課程號,成績

22、查詢沒學(xué)過“葉平”老師課程的學(xué)生姓名以及選修的課程名稱;

23、查詢所有選修了學(xué)號為1的同學(xué)選修過的一門或者多門課程的同學(xué)學(xué)號和姓名;

24、任課最多的老師中學(xué)生單科成績最高的學(xué)生姓名
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容