1 外鍵 外鍵:foreign key,外面的鍵(鍵不在自己表中),如果一張表中有一個欄位(非主鍵)指向另外一張表的主鍵,那麼將該欄位稱為外鍵。 1.1 增加外鍵 外鍵可以在創建表的時候或創建表之後增加(但是要考慮數據的問題)。 方案一:在創建表的時候增加外鍵,在所有的表欄位之後,使用foreign ...
1 外鍵
- 外鍵:foreign key,外面的鍵(鍵不在自己表中),如果一張表中有一個欄位(非主鍵)指向另外一張表的主鍵,那麼將該欄位稱為外鍵。
1.1 增加外鍵
- 外鍵可以在創建表的時候或創建表之後增加(但是要考慮數據的問題)。
- 方案一:在創建表的時候增加外鍵,在所有的表欄位之後,使用foreign key(外鍵欄位) references 外部表 (主鍵欄位);
-- 創建班級 CREATE TABLE my_class( id INT PRIMARY KEY AUTO_INCREMENT, c_name VARCHAR(20) NOT NULL, room VARCHAR(20) ); -- 創建學生表 CREATE TABLE my_student1( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) NOT NULL, c_id INT , CONSTRAINT fk_c_id FOREIGN KEY (c_id) REFERENCES my_class (id) );
- 方案二:在新增表之後,增加外鍵,所以需要修改表結構。
alter table 表名 add [constraint 外鍵名字] foreign key (外鍵欄位) references 父表(主鍵欄位);
-- 創建班級 CREATE TABLE my_class( id INT PRIMARY KEY AUTO_INCREMENT, c_name VARCHAR(20) NOT NULL, room VARCHAR(20) ); -- 創建學生表 CREATE TABLE my_student2( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) NOT NULL, c_id INT ); ALTER TABLE my_student2 ADD CONSTRAINT fk_c_id FOREIGN KEY (c_id) REFERENCES my_class (id);
1.2 修改外鍵&刪除外鍵
- 外鍵不可以修改:只能先刪除後新增。
alter table 表名 drop foreign key 外鍵名;--一張表中可以有多個外鍵,但是名字不能相同
ALTER TABLE my_student2 DROP FOREIGN KEY fk_c_id;
1.3 外鍵作用
- 外鍵預設的作用有兩點:
- 一個對父表:父表數據進行寫操作(刪和改,都必須設計到主鍵本身),如果對應的主鍵在字表中已經被數據所引用,那麼就不允許操作。
- 一個對字表(外鍵欄位所在的表):字表數據進行寫操作(增和改)的時候,如果對應的外鍵欄位在父表找不到對應的匹配,操作會失敗。
1.4 外鍵條件
- 外鍵要存在:首先必須表的存儲引擎是innodb。如果不是innodb存儲引擎,那麼外鍵可以創建成功,但是沒有約束效果。
- 外鍵欄位的欄位類型(列類型)必須和父表的主鍵類型完全一致。
- 一張表中的外鍵名字不能重覆。
- 增加外鍵的欄位(數據已經存在),必須保證數據和父表主鍵要求對應。
1.5 外鍵約束
- 外鍵約束:就是外鍵的作用。
- 外鍵約束有三種約束模式:都是針對父表的約束
- district:嚴格模式(預設的),父表不能刪除或更新一個已經被子表數據引用的記錄(主鍵)。
- cascade:級聯模式,父表的操作,對應子表關聯的數據也隨之變化。
- set null:置空模式,父表的操作之後,子表對應的數據(外鍵)被置空。
- 通常:父表刪除的時候,子表置空;更新的時候,子表級聯操作。
constraint 外鍵名字 foreign key (外鍵欄位) references 主表(主鍵) on delete set null;
constraint 外鍵名字 foreign key (外鍵欄位) references 主表(主鍵) on update cascade;
constraint 外鍵名字 foreign key (外鍵欄位) references 主表(主鍵) on delete set null on update cascade;
- 刪除置空的前提:外鍵欄位為空(如果不滿足條件,外鍵無法創建)。
- 外鍵雖然很強大,能夠進行各種約束,但是對於java來說,外鍵約束降低了java對數據的可控性。所以,通常情況下,在實際開發中,很少使用外鍵的級聯模式和置空模式。
2 聯合查詢
- 聯合查詢:將多次查詢語句,在記錄上進行拼接。
- 基本語法
多條select語句構成:每一條select語句獲取的欄位必須嚴格一致(但是欄位類型無關)
select 語句1 union [union 選項] 語句2……; -- union選項:與select選項一樣有兩個 -- all 保留所有(不管重覆) -- distinct 去重(整個重覆):預設的
- 示例:聯合查詢
SELECT * FROM my_class UNION SELECT * FROM my_class;
- 示例:聯合查詢
SELECT id,c_name,room FROM my_class UNION SELECT id,c_id,NAME FROM my_student2;
- 聯合查詢的意義
- 查詢同一張表,但是需求不同:如查詢學生信息,男生身高升序,女生身高降序(面試題)。
- 多表查詢:多張表的結構是完全一樣的,保存的數據(結構)也是一樣的。
- 聯合查詢Order by使用
- 在聯合查詢中:order by不能直接使用,需要對查詢語句使用括弧才行。
(SELECT * FROM my_student2 WHERE sex = '男' ORDER BY height ASC) UNION (SELECT * FROM my_student2 WHERE sex = '女' ORDER BY height DESC);
-
- 如果想order by生效:必須搭配limit,limit使用限定的最大數即可。
(SELECT * FROM my_student2 WHERE sex = '男' ORDER BY height ASC LIMIT 999999999) UNION (SELECT * FROM my_student2 WHERE sex = '女' ORDER BY height DESC LIMIT 999999999);
3 子查詢
- 子查詢:查詢是在某個查詢結果之上進行的(一條select語句內部包含了另外一條select語句)。
- 子查詢分類方式:
- 按位置分類:子查詢(select語句)在外部查詢(select語句)中出現的位置。
- From子查詢:子查詢在From之後
- where子查詢:子查詢出現在where條件中
- exists子查詢:子查詢出現在exists裡面
- 按照結果分類:根據子查詢得到的數據進行分類(理論上任何一個查詢得到的結果都可以理解為二維表)
- 標量子查詢:子查詢得到的結果是一行一列。(出現在where之後)
- 列子查詢:子查詢得到的結果是一列多行。(出現在where之後)
- 行子查詢:子查詢得到的結果是多列一行(多行多列)(出現在where之後)
- 表子查詢:子查詢得到的結果是多行多列(出現的位置在From之後)
- 按位置分類:子查詢(select語句)在外部查詢(select語句)中出現的位置。
- 示例腳本
-- 創建班級表 CREATE TABLE my_class( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵', c_name VARCHAR(20) NOT NULL COMMENT '班級名字', room VARCHAR(20) NOT NULL COMMENT '班級所在教室' ); -- 插入班級信息 INSERT INTO my_class VALUES (NULL,'java001班','A01'); INSERT INTO my_class VALUES (NULL,'Linux003班','C15'); INSERT INTO my_class VALUES (NULL,'c005班','B23'); -- 創建學生表 CREATE TABLE my_student( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主鍵', NAME VARCHAR(20) NOT NULL COMMENT '學生姓名', age INT NOT NULL COMMENT '學生年齡', gender VARCHAR(2) NOT NULL COMMENT '學生性別', c_id INT COMMENT '外鍵' , CONSTRAINT fk_c_id FOREIGN KEY (c_id) REFERENCES my_class (id) ); -- 插入學生信息 INSERT INTO my_student VALUES (NULL,'張三',20,'男',1); INSERT INTO my_student VALUES (NULL,'李四',18,'女',2); INSERT INTO my_student VALUES (NULL,'王五',19,'女',2); INSERT INTO my_student VALUES (NULL,'趙六',25,'男',3); INSERT INTO my_student VALUES (NULL,'田七',14,'女',1); INSERT INTO my_student VALUES (NULL,'王八',19,'男',3);
3.1 標量子查詢
- 示例:查詢java001班的所有學生。
- ①確定數據源:獲取所有的學生
select * from my_student where c_id = ?;
-
- ②獲取班級id:可以通過名字確定。
SELECT id FROM my_class WHERE c_name = 'java001班' ; -- 一行一列
-
- ③最後的執行SQL語句
SELECT * FROM my_student WHERE c_id = (SELECT id FROM my_class WHERE c_name = 'java001班' );
3.2 列子查詢
- 示例:查詢所有在讀班級的學生(班級表中存在的班級)
- ①確定數據源:學生
SELECT *FROM my_student WHERE c_id IN (?);
-
- ②確定有效班級的id:所有班級的id
SELECT id FROM my_class
-
- 最後的執行SQL語句
SELECT *FROM my_student WHERE c_id IN (SELECT id FROM my_class);
- 列子查詢返回的結果會比較:一列多行,需要使用in作為條件匹配:其實在mysql中還有幾個類似的條件:all、some、any。
3.3 行子查詢
- 行子查詢:返回的結果可以是多行多列(一行多列)
- 修改學生表
ALTER TABLE my_student ADD height INT NOT NULL COMMENT '身高'; UPDATE my_student SET height = 180 WHERE id = 1; UPDATE my_student SET height = 170 WHERE id = 2; UPDATE my_student SET height = 165 WHERE id = 3; UPDATE my_student SET height = 190 WHERE id = 4; UPDATE my_student SET height = 155 WHERE id = 5; UPDATE my_student SET height = 160 WHERE id = 6;
- 示例:要求查詢整個學生中,年齡最大且身高
- 思路1:
- ①確定數據源
- 思路1:
select * from my_student where age = ? and height = ?;
-
-
- ②確定最大的年齡和最高的身高
-
select max(age),max(height) from my_student;
-
-
- ③最後的SQL執行語句
-
SELECT * FROM my_student WHERE (age = (SELECT MAX(age) FROM my_student)) AND (height = (SELECT MAX(height) FROM my_student));
-
-
- ④貌似上面的是對的哦,但是如果最高的年齡最大,身高最高的不是一個人呢?這樣就不能查到數據呢,所以,綜上所述,上面的思路貌似正確,但是不合題意。
- 思路2:正確解法
- 需要構造行元素:行元素是由多個欄位構成。
-
SELECT * FROM my_student WHERE (age,height) = (SELECT MAX(age),MAX(height) FROM my_student);
3.4 表子查詢
- 表子查詢:子查詢返回的結果是當做二維表來使用。
- 示例:找出每個班中最高的一個學生。
- ①先對學生按照身高降序
SELECT * FROM my_student ORDER BY height DESC
-
- ②對排序後的學生臨時表按照班級分組
SELECT * FROM (SELECT * FROM my_student ORDER BY height DESC) AS student GROUP BY student.c_id;
-
- 當然,這一題可能有人會這樣想?我先對學生分組,求出最大的年齡,然後用in子句,就可以了。
SELECT * FROM my_student WHERE height IN (SELECT MAX(height) FROM my_student GROUP BY c_id);
-
- 當然,第二種思路也是可以的。
3.5 exists子查詢
- exists:是否存在,exists子查詢是用來判斷某些條件是否滿足(跨表),exists是在where之後,exists返回的結果是0或1。
- 示例:查詢所有的學生,前提條件是班級存在。
- ①確定數據源
SELECT * FROM my_student WHERE ?;
-
- ②確定條件是否滿足
EXISTS(SELECT * FROM my_class)
-
- 最後的執行SQL語句
SELECT * FROM my_student WHERE EXISTS(SELECT * FROM my_class);