MySQL數據庫03 數據庫查詢語句彙總

DQL 查詢

基礎數據

CREATE TABLE `dept`(
    `deptno` INT(2) NOT NULL, 
    `dname` VARCHAR(14),
    `loc` VARCHAR(13),
    CONSTRAINT pk_dept PRIMARY KEY(deptno)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK'); 
INSERT INTO dept VALUES (20,'RESEARCH','DALLAS'); 
INSERT INTO dept VALUES (30,'SALES','CHICAGO');  
INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON');

CREATE TABLE `emp` (
    `empno` int(4) NOT NULL PRIMARY KEY,
    `ename` VARCHAR(10),  
    `job` VARCHAR(9),  
    `mgr` int(4),  
    `hiredate` DATE,  
    `sal` float(7,2),  
    `comm` float(7,2),  
    `deptno` int(2),
    CONSTRAINT fk_deptno FOREIGN KEY(deptno) REFERENCES dept(deptno)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
INSERT INTO EMP VALUES (7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20); 
INSERT INTO EMP VALUES (7499,'ALLEN','SALESMAN',7698,'1981-02-20',1600,300,30);
INSERT INTO EMP VALUES (7521,'WARD','SALESMAN',7698,'1981-02-22',1250,500,30); 
INSERT INTO EMP VALUES (7566,'JONES','MANAGER',7839,'1981-04-02',2975,NULL,20); 
INSERT INTO EMP VALUES (7654,'MARTIN','SALESMAN',7698,'1981-09-28',1250,1400,30); 
INSERT INTO EMP VALUES (7698,'BLAKE','MANAGER',7839,'1981-05-01',2850,NULL,30); 
INSERT INTO EMP VALUES (7782,'CLARK','MANAGER',7839,'1981-06-09',2450,NULL,10); 
INSERT INTO EMP VALUES (7788,'SCOTT','ANALYST',7566,'1987-07-13',3000,NULL,20); 
INSERT INTO EMP VALUES (7839,'KING','PRESIDENT',NULL,'1981-11-07',5000,NULL,10); 
INSERT INTO EMP VALUES (7844,'TURNER','SALESMAN',7698,'1981-09-08',1500,0,30); 
INSERT INTO EMP VALUES (7876,'ADAMS','CLERK',7788,'1987-07-13',1100,NULL,20); 
INSERT INTO EMP VALUES (7900,'JAMES','CLERK',7698,'1981-12-03',950,NULL,30); 
INSERT INTO EMP VALUES (7902,'FORD','ANALYST',7566,'1981-12-03',3000,NULL,20); 
INSERT INTO EMP VALUES (7934,'MILLER','CLERK',7782,'1982-01-23',1300,NULL,10);

CREATE TABLE `salgrade` (  
    `grade` int, 
    `losal` int,  
    `hisal` int
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
 
INSERT INTO SALGRADE VALUES (1,700,1200); 
INSERT INTO SALGRADE VALUES (2,1201,1400); 
INSERT INTO SALGRADE VALUES (3,1401,2000); 
INSERT INTO SALGRADE VALUES (4,2001,3000); 
INSERT INTO SALGRADE VALUES (5,3001,9999);

基礎數據表分析

emp 員工表

字段名 employee 解釋說明 備註
empno 員工編號
ename 員工姓名
job 工作種類 CLERK 辦事員
SALESMAN 推銷員
MANAGER 經理
ANALYST 研究員
PRESIDENT 董事長
mgr 經理上司 該字段指向的是 另外一名員工的編號
hiredate 入職時間 mysql 中的日期類型
sal 工資
comm 獎金 有null 值存在較多的字段
deptno 部門編號 指向另外的一些表數據

部門表

dept 描述
deptno 部門編號
dname 部門名稱 ACCOUNTING 會計
RESEARCH 研究所
SALES 銷售部
OPERATIONS 運營部
loc 地址

工資等級表

salgrade
grade 等級編號
losal 最低工資
hisal 最高工資

簡單查詢

基礎查詢

select [字段] from 表名

select * from emp; 
#  查詢所有數據 在數據量很龐大的情況下, 效率低, 不推薦使用
# 指定查詢字段 (使用逗號隔開)
select empno,ename.sal from emp;

as 子句

# 更改表頭
select empno as 編號,ename as 姓名 ,sal as 工資 from emp;
# 給表起別名
select e.empno,e.ename,e.sal from emp as e;

as 可以省略不寫

select empno 編號,ename 姓名 ,sal 工資 from emp;

distinct 關鍵字

# 查看 emp 表中的工作種類
select job 工作 from emp;
# 去除工作中重複性的數據
select distinct job 工作 from emp;

每一個字段都相同,纔可以去除重複

在返回結果中使用表達式(函數)

# 所有員工的工資漲薪 10%
select ename 姓名,sal 工資 from emp;
select ename 姓名,sal*1.1 工資 from emp;
select 456*123;  // 不依賴於任何一張表

條件查詢

語法 select [字段] from 表名 [where 條件]

比較運算符

> < >= <= = != 
判斷是否爲空  is null / is not null
between and  在什麼與什麼之間 相當於 >= && <= 
in 在集合範圍內
like  像  模糊查詢

基本比較

查詢工資大於 2000 的所有員工

select * from emp where sal > 2000

查詢工作爲辦事員的 所有員工

select * from emp where job = 'clerk'

查詢入職時間 在1981年5月份之後入職的所有員工的姓名以及 入職時間

select ename "姓名" , hiredate "入職時間" from emp
where hiredate > '1981-05-31'

is null

查詢 沒有上級的 員工的編號和職位

select empno "編號" , job "職位" from emp where mgr is null;

查詢 獎金不爲null 的 所有員工

select * from emp where comm is not null;

between and

查詢工資在1000 到2000 之間的員工的姓名和工資

select ename,sal from emp where sal between 1000 and 2000;
  • 左右邊界都包含在內
  • 小值在前, 大值在後

in

查詢工作爲 辦事員或者是 銷售員的員工

select * from emp where job = 'CLERK' or job = 'SALESMAN';
select * from emp where job in ('CLERK','SALESMAN');

查詢 20號和30號部門中的所有員工

select * from emp where deptno in (20,30);

like 模糊查詢

佔位符

  • % 任意字符 0個或多個
  • (_) 一個任意字符

查詢姓名中帶有 A 字符的 所有員工

select * from emp where ename like '%A%';

查詢姓名中首字母爲 A 字符的所有員工

select * from emp where ename like 'A%';

查詢姓名中 第二個字母爲A的所有員工

select * from emp where ename like '_A%';

注意

# 如果說
select * from emp where ename like 'A'; 
相當於 
select * from emp where ename = 'A'; 

邏輯運算符

and && 
or  || 
not !

查詢入職時間早於1981 年5月, 並且職位爲經理的員工

select * from emp WHERE hiredate < '1981-05-01' and job = 'MANAGER'

排序查詢

語法: order by 需要排序的字段 指定規則(默認升序), 第二個需要排序的字段

  • 可以根據字段名 排序
  • 可以根據 字段的別名排序
  • 根據字段的位置編號排序

查詢所有員工信息, 按照工資升序排列

select * from emp order by sal ;
select * from emp order by sal desc;

查詢所有員工信息, 按照工資升序排列,如果工資相同, 再按照入職時間降序排序

select * from emp order by sal , hiredate desc;

按照員工編號降序 查詢所有員工信息

select * from emp order by 1 desc;
select empno 編號 , enamel from emp order by 編號 desc;

分頁查詢(限定查詢)

語法 語句的最後使用 分頁

limit [m ,] n 從第m條記錄開始 查詢, 一共返回 n條數據

如果m 項不指定, 默認爲 0

查詢工資最高的5 名員工

select * from emp order by sal desc limit 5;

查詢工資從高到低排名第7 - 10 位的的4 名員工

select * from emp order by sal desc limit 6,4;

查詢職位爲 銷售員的 並且總工資高於 1500 的前三名員工, 按照工資降序排列

select * from emp 
where job = 'SALESMAN' and (sal + comm)> 1500
order by sal desc 
limit 3

Mysql函數

統計函數/聚合函數

函數名 說明
count() 統計, 計數
sum() 求和
avg() 平均數
max() 最大值
min() 最小值

統計emp 表總數據條數

忽略 值爲null 的字段

一般情況下, count() 中 統計那些非空字段 (主鍵)

select count(*) from emp; # 返回值爲一個數字
select count(1) from emp;
SELECT COUNT(empno) FROM emp;

統計該公司所有員工的總工資

select sum(sal) from emp;

統計該公司的平均工資

select sum(sal)/count(empno) from emp;
select avg(sal) from emp;

統計最高工資和 最低工資

select max(sal), min(sal) from emp;

數學函數

abs(n) 
返回n的絕對值  
mod(n,m)   
取模運算,返回n被m除的餘數(同%操作符)  
floor(n) 
返回不大於n的最大整數值  
ceiling(n) 
返回不小於n的最小整數值  
round(n,d) 
返回n的四捨五入值,保留d位小數(d的默認值爲0)  
truncate(n,d)   
保留數字n的d位小數並返回  
pow(x,y)   
power(x,y)   
 返回值x的y次冪 
sqrt(n) 
 返回非負數n的平方根  
pi()   
 返回圓周率  
rand() 
rand(n)   
返回在範圍0到1.0內的隨機浮點值(可以使用數字n作爲初始值) 

計算 2的31次冪

select pow(2,31);  # 不依賴於任何表 , 不需要寫from  
# 但是oracle 數據庫需要添加虛表
# 獲取隨機數 0-1
select rand();
# 獲取 5-10 之間的隨機數
SELECT ROUND(RAND()*5+5);

字符串函數

length(str)
ascii(str)  
返回字符串str的第一個字符的ascii值(str是空串時返回0)  
concat(str1,str2,...)  
把參數連成一個長字符串並返回(任何參數是null時返回null)  
substring(str,pos,len)  
substring(str from pos for len)   
replace(str,from_str,to_str)  
用字符串to_str替換字符串str中的子串from_str並返回  
trim([[both | leading | trailing] [remstr] from] str)  
返回前綴或後綴remstr被刪除了的字符串str(位置參數默認both,remstr默認值爲空格) 

查詢員工中 名字字符長度爲 5 的所有員工

select * from emp where length(ename) = 5

查詢員工的姓名和工資, 以如下格式顯示 (XXX的工資是: 0.00)

select ename,sal from emp;
select concat(ename,'的工資是: ',sal) from emp;

把所有員工姓名中 的A字符 全部隱藏

select replace(ename,'A','') from emp;

日期函數

now()   
sysdate()   
current_timestamp() 
 以'yyyy-mm-dd hh:mm:ss'或yyyymmddhhmmss格式返回當前日期
時間(根據返回值所處上下文是字符串或數字)     
curtime()   
current_time() 
 以'hh:mm:ss'或hhmmss格式返回當前時間值(根據返回值所處上
下文是字符串或數字)      
curdate()    
current_date() 
 以'yyyy-mm-dd'或yyyymmdd格式返回當前日期值(根據返回值所
處上下文是字符串或數字)    
month(date)   
返回date中的月份數值    
datediff(now(),hiredate)  判斷兩個日期之間相隔天數 (大日期在前, 小日期在後)

timestampdiff(日月年等參數, 兩個日期參數小日期在前, 大日期在後)
	判斷兩個日期之間相隔的 年月日 
	
adddate(時間參數 interval 3 month) 日期累加
last_day()  當前月的最後一天

獲取系統當前時間

select now();
select sysdate() ;

插入數據

insert into emp (empno,ename,hiredate,sal) values (9527,'孫繼斌',now(),6000); 
delete from emp where empno = 9527;

統計五月份入職的員工

select * from  emp where month(hiredate) = 5;

查詢所有員工入職的天數

select datediff(now(),hiredate) from emp;
#查詢入職的天數大於 13000 的所有員工
select * from emp where datediff(now(),hiredate) > 13000

查看100 天之後的日期

# 加 100 天
select adddate(now(), interval 100 day);
# 加 三個 月
select adddate(now(), interval 3 month);
# 加 100 天 簡寫
select adddate(now(),100);

轉換函數

字符串轉日期 str_to_date(字符串, 日期格式)
日期轉字符串 date_format(date,format)   
 根據format字符串格式化date值  

查詢當前系統時間

select now();
# 格式化 日期
select date_format(now(),'%Y年%m月%d號 %H:%i:%s');

把字符串轉換爲日期

select str_to_date('2008年08月08號','%Y年%m月%d號')

隱式轉換

SELECT '5'+3 ;  # 結果爲 8
# 如果 日期的書寫格式 爲 '2019-07-25'  能夠自動轉換爲 日期格式
select * from emp where hiredate > '1981-05-01'

系統函數

ifnull(字段名,如果爲null 需要替換的值)
UUID()  隨機字符串數 絕對不可能重複的隨機字符串 
	通過電腦硬件編碼和當前系統時間 
MD5()  加密函數
給淘寶網訂單表添加 隨機的字符串訂單號
select uuid();

行列轉換函數

案例準備

create table t_score
(
  name varchar(20) ,
  subject varchar(20),
  score float
);
INSERT INTO `t_score` VALUES
    ('王海', '語文', '86'),
    ('王海', '數學', '83'),
    ('王海', '英語', '93'),
    ('陶俊', '語文', '88'),
    ('陶俊', '數學', '84'),
    ('陶俊', '英語', '94'),
    ('劉可', '語文', '80'),
    ('劉可', '數學', '86'),
    ('劉可', '英語', '88'),
    ('李春', '語文', '89'),
    ('李春', '數學', '80'),
    ('李春', '英語', '87');

實現效果

SELECT NAME 姓名, 
	CASE SUBJECT WHEN '語文' THEN score END 語文,
	CASE SUBJECT WHEN '數學' THEN score END 數學,
	CASE SUBJECT WHEN '英語' THEN score END 英語
FROM t_score;

使用分組去除 重複的姓名

SELECT NAME 姓名, 
	CASE SUBJECT WHEN '語文' THEN score END 語文,
	CASE SUBJECT WHEN '數學' THEN score END 數學,
	CASE SUBJECT WHEN '英語' THEN score END 英語
FROM t_score
group by name;

繼續優化 去除null 值

SELECT NAME 姓名, 
	max(CASE SUBJECT WHEN '語文' THEN score END) 語文,
	max(CASE SUBJECT WHEN '數學' THEN score END) 數學,
	max(CASE SUBJECT WHEN '英語' THEN score END) 英語
FROM t_score
group by name;

複雜查詢

子查詢

在查詢語句中的WHERE條件子句中,又嵌套了另外一個查詢語句

一個語句 查詢條件 依賴於另外一條語句的 結果

單行單列

職位和 SMITH 先生 職位相同的所有員工

分步查詢
1- 查詢 SMITH 職位
select job from emp where ename = 'SMITH';
2- 查詢 職位爲 該職位的所有員工
select * from emp 
where job = (select job from emp where ename = 'SMITH') 
	and ename != 'SMITH'

查詢入職時間 早於 JAMES 的 所有員工

select * from emp 
where hiredate < (select hiredate from emp where ename = 'JAMES')

查詢 和SMITH 部門相同的員工

select * from emp 
where deptno = (select deptno from emp where ename = 'SMITH')

單列多行

查詢和 SMITH 或者 WARD 工作部門相同的所有員工

1- SMITH 或者 WARD 工作部門
select deptno from emp where ename = 'SMITH' or ename = 'WARD'
2- 所有員工
select * from emp 
where deptno in (select deptno from emp where ename = 'SMITH' or ename = 'WARD')

單行多列

查詢和SMITH 工作相同 部門也相同的員工

1- 查詢SMITH 工作, 部門
select job , deptno from emp where ename = 'SMITH'
2- 
select * from emp 
where (job,deptno) = (select job , deptno from emp where ename = 'SMITH')

多行多列

查詢人數最多的部門, 有多少人

# 分組查詢出每個部門的人數
select deptno,count(empno)
from emp 
group by deptno 
# 把以上表的查詢結果 當成一張新表來查詢
select  max(ct)
from (SELECT deptno,COUNT(empno) ct FROM emp GROUP BY deptno ) newtable

作爲一個字段來存在

(基於多表查詢) 列出 員工姓名以及其 上司的姓名

select e.ename 員工,(select m.ename from emp m where e.mgr = m.empno) 上司 from emp e

分組查詢

按照某些字段分組, 按照各個組, 分別統計查詢

查詢10 號部門的員工人數

select count(empno) from emp where deptno = 10

查詢各個部門的員工人數

#先按照部門分組  每個部門多少人
select deptno,count(empno) from emp group by deptno

注意:

使用group by 分組, 不允許在select 中 隨意添加字段

  • 在group by 中出現的字段可以添加
  • 統計函數 可以添加

統計各種工作種類的員工人數

select count(empno) from emp group by job

統計每個部門的平均工資, 最高/最低工資

select deptno, avg(sal),max(sal),min(sal) from emp group by deptno

查詢語句的執行順序

select  deptno
from emp
where sal > 1000
group by deptno
order by hiredate 
limit 5
查詢步驟
1- from
2- where 篩選
3- group by 按照某字段分組
4- select 列出要查看的字段
5- having 在分組之後執行的 篩選條件
6- order by 
7- limit

驗證語句的執行順序

按照總工資排序所有員工

select ename 員工姓名,sal+comm 總工資 from emp order by 總工資
# null 不能和 其他值做運算

徵兵 先體檢 你滿足的當兵的基本條件 , 分配兵種

where 篩選 要在分組前執行

統計函數 , 每個分組都有自己的統計結果, 統計函數是在分組之後開始執行的

where中 一定不允許出現 統計函數

having

查詢平均工資 大於2000 的部門編號

# 1- 先獲取所有部門的平均工資
# 2- 查詢平均工資 > 2000
select deptno , avg(sal) from emp 
group by deptno having avg(sal) > 2000

having 和 where的對比

  1. 兩者都是篩選條件
  2. where 在分組之前執行 having 在分組之後執行
  3. where 中不能出現分組函數(統計函數) , having 可以使用該函數

查詢 平均工資 最高的部門編號

# 1- 先獲取所有部門的平均工資
select deptno , avg(sal)  from emp group by deptno 
# 2- 查詢出最高的平均工資
select max(asl) from (select deptno , avg(sal) asl  from emp group by deptno) nt 
# 3- 該平均工資的部門
select deptno from emp group by deptno 
having avg(sal) = (select max(asl) from (select deptno , avg(sal) asl  from emp group by deptno) nt )

第二種方式
SELECT deptno ,MAX(nt.asl) FROM (SELECT deptno , AVG(sal) asl  FROM emp GROUP BY deptno) nt

多表查詢

員工表

部門表

工資等級表

笛卡爾積

假設集合A={a, b},集合B={0, 1, 2},

則兩個集合的笛卡爾積爲{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。

查詢兩個數據表數據, 查詢結果是把所有的可能

通過連接條件避免出現笛卡爾積

多表查詢

  • 給數據庫表起別名, 便於引用
  • 如果要查詢的字段沒有重複, 可以不指定表名

查詢員工所有信息,以及該員工工作的部門信息

select emp.*, dept.* from emp , dept

第一種語法格式

select emp.*, dept.* from emp , dept where emp.deptno = dept.deptno;
# 給數據庫表起別名, 便於引用
# 如果要查詢的字段沒有重複, 可以不指定表名
select e.*, d.* from emp e, dept d where e.deptno = d.deptno;

第二種語法格式

select e.*, d.* from emp e join dept d on e.deptno = d.deptno
# 相當於
select e.*, d.* from emp e inner join dept d on e.deptno = d.deptno

分類

內連接

在表中至少一個匹配時,則返回記錄

給emp 添加一條沒有部門信息的員工

insert into emp (empno,ename,hiredate,sal) values (10086,'支音',now(),10000);

查詢員工的所有信息以及 該員工的工資等級

select e.*,s.grade
from emp e join salgrade s
on e.sal between s.losal and s.hisal

外鏈接

左外連接

從左表中返回所有的記錄,即便在右中沒有匹配的行

select e.*, d.* from emp e left join dept d on e.deptno = d.deptno

右外連接

select e.*, d.* from emp e right join dept d on e.deptno = d.deptno

全外連接(MySql 不支持, Oracle 支持)

select e.*, d.* from emp e full join dept d on e.deptno = d.deptno

三表查詢案例

查詢員工的所有信息, 和所屬部門的所有信息, 和工資等級

select e.*, d.* ,s.grade
from emp e 
join dept d on e.deptno = d.deptno 
join salgrade s on e.sal between s.losal and hisal
select e.*, d.* ,s.grade
from emp e, dept d, salgrade s
where e.deptno = d.deptno and e.sal between s.losal and hisal

自連接查詢

獲取emp表中 所有 員工的姓名 以及該員工上司的姓名

select e.ename,m.ename
from emp e, emp m
where e.mgr = m.empno
select concat(e.ename,'的上司是: ',m.ename)
from emp e, emp m
where e.mgr = m.empno

聯合查詢

# 兩次的查詢結果 取並集

查詢20 號部門和30 號部門的所有員工

# 以前的寫法
select * from emp where deptno = 20 or deptno = 30;
select * from emp where deptno in (20,30);

使用並集

select * from emp where deptno = 20
union
select * from emp where deptno = 30;

使用並集 模擬 全外連接

select e.*, d.* from emp e left join dept d on e.deptno = d.deptno
union 
select e.*, d.* from emp e right join dept d on e.deptno = d.deptno;

數據庫設計

學生表

姓名
年齡
性別
電話
銀行卡 
手機卡

銀行卡

銀行卡號
所屬銀行
卡餘額
開通業務
存取款流水

手機卡

手機卡號
所屬運營商
餘額
充值記錄

第一範式 : 每列都是不可再分的最小數據單元

第二範式: 要求每個表只描述一件事情

第三範式: 除了主鍵以外的其他列都直接依賴於主鍵列

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章