SQL (二)


 

一、數據場景查詢

1.1 排序

通過 ORDER BY 子句,可以將查詢出的結果進行排序(排序只是顯示方式,不會影響數據庫中數據的順序)
SELECT 字段名 FROM 表名 WHERE 字段=ORDER BY 字段名 

[ASC|DESC];
ASC: 升序,默認值
DESC: 降序

單列排序, 什么是單列排序:只按某一個字段進行排序,單列排序。

  練習:使用年齡降序排序

組合排序,同時對多個字段進行排序,如果第 1 個字段相等,則按第 2 個字段排序,依次類推。

-- 組合排序的語法:
SELECT 字段名 FROM 表名 WHERE 字段=ORDER BY 字段名 1 [ASC|DESC], 字段名 2 [ASC|DESC];

  練習:查詢所有數據,在年齡降序排序的基礎上,如果年齡相同再以數學成績升序排序

 

1.2 聚合函數

之前我們做的查詢都是橫向查詢,它們都是根據條件一行一行的進行判斷,而使用聚合函數查詢是縱向查詢,它是對一列的值進行計算,然后返回一個結果值。聚合函數會忽略空值 NULL

-- 語法
SELECT 聚合函數(列名) FROM 表名;

練習:查詢學生總數

我們發現對於 NULL 的記錄不會統計,建議如果統計個數則不要使用有可能為 null 的列,但如果需要把 NULL也統計進去呢?
IFNULL(列名,默認值) 如果列名不為空,返回這列的值。如果為 NULL,則返回默認值。

練習:查詢 id 字段,如果為 null,則使用 0 代替

我們可以利用 IFNULL()函數,如果記錄為 NULL,給個默認值,這樣統計的數據就不會遺漏 練習:
1.查詢年齡大於 20 的總數
2.查詢數學成績總分
3.查詢數學成績平均分
4.查詢數學成績最高分
5.查詢數學成績最低分

1.3 分組

分組查詢是指使用 GROUP BY 語句對查詢信息進行分組,相同數據作為一組
SELECT 字段 1,字段 2... FROM 表名 GROUP BY 分組字段 [HAVING 條件];
GROUP BY 怎么分組的?
將分組字段結果中相同內容作為一組,如按性別將學生分成 2 組。
GROUP BY 將分組字段結果中相同內容作為一組,並且返回每組的第一條數據,所以單獨分組沒什么用處。分組的目的就是為了統計,一般分組會跟聚合函數一起使用。
注意:當我們使用某個字段分組,在查詢的時候也需要將這個字段查詢出來,否則看不到數據屬於哪組的

練習:

1.按性別進行分組,求男生和女生數學的平均分
2.查詢男女各多少人
3.查詢年齡大於 25 歲的人,按性別分組,統計每組的人數
4.查詢年齡大於 25 歲的人,按性別分組,統計每組的人數,並只顯示性別人數大於 2 的數據
 

having 與 where 的區別

 

 

 

1.4 分頁查詢 limit的作用

准備數據
INSERT INTO student3(id,NAME,age,sex,address,math,english) VALUES
(9,'唐僧',25,'','長安',87,78),
(10,'孫悟空',18,'','花果山',100,66),
(11,'豬八戒',22,'','高老庄',58,78),
(12,'沙僧',50,'','流沙河',77,88),
(13,'白骨精',22,'','白虎嶺',66,66),
(14,'蜘蛛精',23,'','盤絲洞',88,88);
 

limit 的作用

LIMIT 是限制的意思,所以 LIMIT 的作用就是限制查詢記錄的條數。

SELECT *|字段列表 [as 別名] FROM 表名 [WHERE 子句] [GROUP BY 子句][HAVING 子句][ORDER BY 子 句][LIMIT 子句];

 練習:查詢學生表中數據,從第 3 條開始顯示,顯示 6 條。

 

LIMIT 的使用場景:
分頁:比如我們登錄京東,淘寶,返回的商品信息可能有幾萬條,不是一次全部顯示出來。是一頁顯示固定的條數。 假設我們每頁顯示 5 條記錄的方式來分頁。

 

 

二、數據庫表的約束

對表中的數據進行限制,保證數據的正確性、有效性和完整性。一個表如果添加了約束,不正確的數據將無法插入到表中。約束在創建表的時候添加比較合適。

image

 

 

2.1 主鍵

用來唯一標識數據庫中的每一條記錄,通常不用業務字段作為主鍵,單獨給每張表設計一個 id 的字段,把 id 作為主鍵。主鍵是給數據庫和程序使用的,不是給最終的客戶使用的。所以主鍵有沒有含義沒有關系,只要不重復唯一非空就行。

如:身份證,學號不建議做成主鍵
-- 在創建表的時候給字段添加主鍵
字段名 字段類型 PRIMARY KEY

-- 在已有表中添加主鍵
ALTER TABLE 表名 ADD PRIMARY KEY(字段名);

-- 刪除主鍵
alter table 表名 drop primary key;

練習:

1.創建一個學生st1表 字段id,name,age,把id設置為主鍵

2.添加相同主鍵看是否插入

3.刪除主鍵

注:主鍵數在一個表中,只能有一個。不能出現多個主鍵。

 

2.2 主鍵自增

主鍵如果讓我們自己添加很有可能重復,我們通常希望在每次插入新記錄時,數據庫自動生成主鍵字段的值
AUTO_INCREMENT 表示自動增長(字段類型必須是整數類型)
默認地 AUTO_INCREMENT 的開始值是 1,如果希望修改起始值,請使用下列 SQL 語法
-- 創建表時指定起始值
CREATE TABLE 表名(
列名 int primary key AUTO_INCREMENT
) AUTO_INCREMENT=起始值;
-- 指定起始值為 1000

-- 創建好以后修改起始值
ALTER TABLE 表名 AUTO_INCREMENT=起始值;

注:DELETE:刪除所有的記錄之后,自增長沒有影響。TRUNCATE:刪除以后,自增長又重新開始。

 

2.3 唯一約束

什么是唯一約束: 表中某一列不能出現重復的值
-- 唯一約束的基本格式 建表
字段名 字段類型 UNIQUE

-- 建完表添加
alter table 表名 add unique(字段名)

注:null不存在數據,不屬於重復問題

 

2.4 非空約束

什么是非空約束:某一列不能為 null
-- 非空約束的基本語法格式
字段名 字段類型 NOT NULL

2.5 默認值

在表中插入一條新記錄時,如果沒有為某個字段賦值,系統就會自動為這個字段插入默認值。

字段名 字段類型 DEFAULT 默認值

 

2.6 外鍵約束

單表的缺點:創建一個員工表包含如下列(id, name, age, dep_name, dep_location),id 主鍵並自動增長,添加 5 條數據
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
age INT,
dep_name VARCHAR(30),
dep_location VARCHAR(30)
);

-- 添加數據
INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('張三', 20, '研發部', '廣州');
INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('李四', 21, '研發部', '廣州');
INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('王五', 20, '研發部', '廣州');
INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('老王', 20, '銷售部', '深圳');
INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('大王', 22, '銷售部', '深圳');
INSERT INTO emp (NAME, age, dep_name, dep_location) VALUES ('小王', 18, '銷售部', '深圳');

可以看到 以上數據表的缺點:
1) 數據冗余
2)后期還會出現增刪改的問題
 
解決方案: 分表
-- 解決方案:分成 2 張表
-- 創建部門表(id,dep_name,dep_location)
-- 一方,主表
create table department(
id int primary key auto_increment,
dep_name varchar(20),
dep_location varchar(20)
);
-- 創建員工表(id,name,age,dep_id)
-- 多方,從表
create table employee(
id int primary key auto_increment,
name varchar(20),
age int,
dep_id int -- 外鍵對應主表的主鍵
)
-- 添加 2 個部門
insert into department values(null, '研發部','廣州'),(null, '銷售部', '深圳');
select * from department;
-- 添加員工,dep_id 表示員工所在的部門
INSERT INTO employee (NAME, age, dep_id) VALUES ('張三', 20, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('李四', 21, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('王五', 20, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('老王', 20, 2);
INSERT INTO employee (NAME, age, dep_id) VALUES ('大王', 22, 2);
INSERT INTO employee (NAME, age, dep_id) VALUES ('小王', 18, 2);
select * from employee;

 

當我們在 employee 的 dep_id 里面輸入不存在的部門,數據依然可以添加.但是並沒有對應的部門,實際應用中不能出現這種情況。employee 的 dep_id 中的數據只能是 department 表中存在的 id 
 
 
需要約束 dep_id 只能是 department 表中已經存在 id 
解決方式: 使用外鍵約束
什么是外鍵:在從表中與主表主鍵對應的那一列,如:員工表中的 dep_id
主表: 一方,用來約束別人的表
從表: 多方,被別人約束的表 
 

 

 

-- 創建約束的語法
-- 新建表時增加外鍵:
[CONSTRAINT] [外鍵約束名稱] FOREIGN KEY(外鍵字段名) REFERENCES 主表名(主鍵字段名)

-- 已有表增加外鍵:
ALTER TABLE 從表 ADD [CONSTRAINT] [外鍵約束名稱] FOREIGN KEY (外鍵字段名) REFERENCES 主表(主鍵字段名);

-- 2) 創建從表 employee 並添加外鍵約束 emp_depid_fk
-- 多方,從表
create table employee(
id int primary key auto_increment,
name varchar(20),
age int,
dep_id int, -- 外鍵對應主表的主鍵
-- 創建外鍵約束
constraint emp_depid_fk foreign key (dep_id) references department(id)
)
-- 3) 正常添加數據
INSERT INTO employee (NAME, age, dep_id) VALUES ('張三', 20, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('李四', 21, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('王五', 20, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('老王', 20, 2);
INSERT INTO employee (NAME, age, dep_id) VALUES ('大王', 22, 2);
INSERT INTO employee (NAME, age, dep_id) VALUES ('小王', 18, 2);
select * from employee;
-- 4) 部門錯誤的數據添加失敗
-- 插入不存在的部門
-- Cannot add or update a child row: a foreign key constraint fails
INSERT INTO employee (NAME, age, dep_id) VALUES ('老張', 18, 6);

 

刪除外鍵

ALTER TABLE 從表 drop foreign key 外鍵名稱;

然后在alter添加.....

 

外鍵的級聯

在修改和刪除主表的主鍵時,同時更新或刪除副表的外鍵值,稱為級聯操作
 
要把部門表中的 id 值 2,改成 5,能不能直接更新呢? 
要刪除部門 id 等於 1 的部門, 能不能直接刪除呢? 
 
-- 刪除 employee 表,重新創建 employee 表,添加級聯更新和級聯刪除
drop table employee;

create table employee(
id
int primary key auto_increment,
name
varchar(20),
age
int,
dep_id
int, -- 外鍵對應主表的主鍵
--
創建外鍵約束
constraint emp_depid_fk foreign key (dep_id) references
department(id)
on update cascade on delete cascade
)

-- 再次添加數據到員工表和部門表
INSERT INTO employee (NAME, age, dep_id) VALUES ('張三', 20, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('李四', 21, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('王五', 20, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('老王', 20, 2);
INSERT INTO employee (NAME, age, dep_id) VALUES ('大王', 22, 2);
INSERT INTO employee (NAME, age, dep_id) VALUES ('小王', 18, 2);

-- 刪除部門表?能不能直接刪除?
drop table department;
-- 把部門表中 id 等於 1 的部門改成 id 等於 10
update department set id=10 where id=1;
select from employee;
select
from department;
-- 刪除部門號是 2 的部門
delete from department where id=2;

 

 

三 、多表查詢

數據准備

-- 創建部門表
create table dept(
 id int primary key auto_increment,
 name varchar(20)
);
insert into dept (name) values ('開發部'),('市場部'),('財務部'); 

-- 創建員工表
create table emp (
id
int primary key auto_increment,
name
varchar(10),
gender
char(1), -- 性別
salary double, -- 工資
join_date date, -- 入職日期
dept_id int
);


insert into emp(name,gender,salary,join_date,dept_id) values('孫悟空','',7200,'2013-02-24',1);
insert into emp(name,gender,salary,join_date,dept_id) values('豬八戒','',3600,'2010-12-02',2);
insert into emp(name,gender,salary,join_date,dept_id) values('唐僧','',9000,'2008-08-08',2);
insert into emp(name,gender,salary,join_date,dept_id) values('白骨精','',5000,'2015-10-07',3);
insert into emp(name,gender,salary,join_date,dept_id) values('蜘蛛精','',4500,'2011-03-14',1);

 

多表查詢的作用:
比如:我們想查詢孫悟空的名字和他所在的部門的名字,則需要使用多表查詢。
如果一條 SQL 語句查詢多張表,因為查詢結果在多張不同的表中。每張表取 1 列或多列。

image

 

 

笛卡爾積現象

-- 需求:查詢所有的員工和所有的部門
select * from emp,dept;

我們發現不是所有的數據組合都是有用的,只有員工表.dept_id = 部門表.id 的數據才是有用的。所以需要通過條件過濾掉沒用的數據。
-- 設置過濾條件 Column 'id' in where clause is ambiguous
select * from emp,dept where id=5;
select * from emp,dept where emp.'dept_id' = dept.'id';
-- 查詢員工和部門的名字 select emp.`name`, dept.`name` from emp,dept where emp.'dept_id' = dept.'id';

 

3.1、內連接

用左邊表的記錄去匹配右邊表的記錄,如果符合條件的則顯示。如:從表.外鍵=主表.主鍵
連接結果僅包含符合連接條件的行,參與連接的兩個表都應該符合連接條件
-- 隱式內連接:看不到 JOIN 關鍵字,條件使用 WHERE 指定
SELECT 字段名 FROM 左表, 右表 WHERE 條件

-- 顯示內連接:使用 INNER JOIN ... ON 語句, 可以省略 INNER
SELECT 字段名 FROM 左表 [INNER] JOIN 右表 ON 條件

需要聯合 2 張表同時才能查詢出需要的數據,使用內連接

 

總結內連接查詢步驟:
1)確定查詢哪些表
2)確定表連接的條件
3)確定查詢的條件
4)確定查詢的字段

 

3.2 外連接

-- 左外連接:使用 LEFT OUTER JOIN ... ON,OUTER 可以省略
SELECT 字段名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 條件
用左邊表的記錄去匹配右邊表的記錄,如果符合條件的則顯示;否則,顯示 NULL
可以理解為:在內連接的基礎上保證左表的數據全部顯示

image

-- 右外連接:使用 RIGHT OUTER JOIN ... ON,OUTER 可以省略
SELECT 字段名 FROM 左表 RIGHT [OUTER ]JOIN 右表 ON 條件
用右邊表的記錄去匹配左邊表的記錄,如果符合條件的則顯示;否則,顯示 NULL
可以理解為:在內連接的基礎上保證右表的數據全部顯示

image

 
注:工作中優先使用左連接
 
 

3.3、UNION

合並兩個或多個 SELECT 語句的結果。

注:UNION 內部的每個 SELECT 語句必須擁有相同數量的列。列也必須擁有相似的數據類型。同時,每個 SELECT 語句中的列的順序必須相同。

SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2;

UNION ALL

SELECT column_name(s) FROM table1
UNION ALL
SELECT column_name(s) FROM table2;

UNION 與 UNION ALL 區別
UNION :相同數據會不顯示 有除重功能
UNION ALL:無論數據是否重復 全部顯示

3.4、 子查詢

 
1) 一個查詢的結果做為另一個查詢的條件
2) 有查詢的嵌套,內部的查詢稱為子查詢
3) 子查詢要使用括號
 
需求:查詢開發部中有哪些員工?
 
子查詢結果的三種情況: 
1) 子查詢的結果是單行單列 
2) 子查詢的結果是多行單列 

 

3) 子查詢的結果是多行多列 

 

 

子查詢的結果是一個值的時候

子查詢結果只要是單行單列,肯定在 WHERE 后面作為條件,父查詢使用:比較運算符,如:> 、<、<>、= 等
SELECT 查詢字段 FROMWHERE 字段=(子查詢);

練習:

1.查詢工資最高的員工是誰?

2.查詢工資小於平均工資的員工有哪些?

 

 子查詢結果是多行單列的時候

子查詢結果是單例多行,結果集類似於一個數組,父查詢使用 IN 運算符
SELECT 查詢字段 FROMWHERE 字段 IN (子查詢);

練習:

1.查詢工資大於 5000 的員工,來自於哪些部門的名字?

2.查詢開發部與財務部所有的員工信息

 

 子查詢的結果是多行多列

子查詢結果只要是多列,肯定在 FROM 后面作為表 
SELECT 查詢字段 FROM (子查詢) 表別名 WHERE 條件;

注:子查詢作為表需要取別名,否則這張表沒有名稱則無法訪問表中的字段

練習:

1.查詢出 2011 年以后入職的員工信息,包括部門名稱 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM