mysql之多表查詢
1.合并結果集
作用:合并結果集就是把兩個select語句查詢的結果連接到一起!
?
/*創建表t1*/
CREATE TABLE t1(a INT PRIMARY KEY ,b VARCHAR(10)
)
INSERT INTO t1 VALUES(1,'a');
INSERT INTO t1 VALUES(2,'b');
INSERT INTO t1 VALUES(3,'c');

/*創建t2*/
CREATE TABLE t2(c INT PRIMARY KEY ,d VARCHAR(10)
)
INSERT INTO t2 VALUES(4,'d');
INSERT INTO t2 VALUES(5,'e');
INSERT INTO t2 VALUES(6,'f');

合并結果集有兩種方式:
union: 去除重復記錄。
/*使用union進行連接兩個select語句*/select * from t1 union select * from t2;
查詢結果為:

?
為了體現去重思想: 我們給t1添加一條數據
insert into t1 values(4,'d');

重新進行查詢則:
select * from t1 union select * from t2;

? ?證明了 t1表和t2表的相同的數據會去掉
union all:不用出去重復記錄。
select * from t1 union all select * from t2;

輸出結果中 ? 4d出現了兩次
總結 : ?union :連接兩個查詢語句 ?去除完全相同的數據
union all: 連接兩個查詢語句,不去除完全相同的記錄
? ? 要求:被合并的兩個結果:列數、列類型必須相同。
2.連接查詢
連接查詢就是求出多個表的乘積 ?eg:t1連接t2,那么查詢出來的結果為t1*t2
select * from t1,t2;

? 連接查詢會產生 ?笛卡爾積
假設集合A={a,b},集合B={0,1,2},則兩個集合的笛卡爾積為{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。可以擴展到多個集合的情況。
為了去除笛卡爾積給我們帶來的多余的數據 ? 我們使用連接查詢 給了一個約束條件(外鍵約束)
為了更好的體驗連接查詢的約束條件 我們重新建了兩個表
create table classes(cid int primary key auto_increment,cname varchar(20),cnum int
);
insert into classes values(null,'01班',20);
insert into classes values(null,'02班',30);
insert into classes values(null,'03班',40);
insert into classes values(null,'04班',41);
create table student(
sid int primary kay auto_increament,
cname varchar(20),
sex varchar(1),
brithday date,
cno int,
constraint fk_st_c1 foreign key (cno) references classes (cid)
);
/*給student表添加數據*/
INSERT INTO student VALUES(NULL,'張三','男','1990-09-01',1);
INSERT INTO student VALUES(NULL,'李四','女','1991-02-13',1);
INSERT INTO student VALUES(NULL,'王五','男','1990-03-12',1);
INSERT INTO student VALUES(NULL,'趙六','男','1992-02-12',2);
INSERT INTO student VALUES(NULL,'田七','男','1994-05-21',2);
INSERT INTO student VALUES(NULL,'張五','女','1990-05-17',2);
INSERT INTO student VALUES(NULL,'張老七','女','1990-06-17',3);
INSERT INTO student VALUES(NULL,'王老四','女','1990-04-12',3);
INSERT INTO student VALUES(NULL,'李六','男','1990-09-12',1);
班級表 ? ? 學生表?
? ? ? ? ? ? ? ? ? ? ? ? ??
?
?學生表中的cno字段的外鍵是班級表中的cid
這樣我們使用連接查詢會產生(班級表的條數*學生表的條數=4*9=36)
SELECT COUNT(*) FROM classes ,student

加上約束條件使沒用的數據過濾掉 ?使用where關鍵字
SELECT COUNT(*) FROM classes c,student s WHERE c.cid=s.cno;

使無效數據過濾掉,所以union 一般我們不會使用
?
因此產生了內連接和外連接查詢
內連接分為: ? (特點 ?查詢條件必須滿足)
顯式內連接(inner join ? .....on) ? 其中 ?inner關鍵字可以省略 ? ?
SELECT * FROM classes c INNER JOIN student s ON c.cid=s.cno;
SELECT * FROM classes c JOIN student s ON c.cid=s.cno; /*省略inner關鍵字*/

隱式內連接
就是我們剛才提到的連接查詢
?
SELECT * FROM classes c,student s WHERE c.cid=s.cno;

外連接?
左外連接: ?左表作為基礎
left outer join ? on
SELECT * FROM classes c LEFT OUTER JOIN student s ON c.cid=s.cno;
把班級表作為基礎 ?查詢出來的結果為:
? ? ? ? ? ? ? ? ? ? ?
右外連接: ?右表作為基礎
right outer join on?
SELECT * FROM classes c RIGHT OUTER JOIN student s ON c.cid=s.cno;
把學生表作為基礎 ?查詢出來的結果為:
? ? ? ? ? ? ? ? ? ? ? ??
?
? ? ? ? 使用一張圖來總結左連接和右連接
?
3.子查詢?
? ? 子查詢:一個select語句中包含了另一個select語句
子查詢的位置
where后 ? :作為條為被查詢的一條件的一部分
?
from 后 ? ? : ? 作表;
?當子查詢出現在where后作為條件時,還可以使用如下關鍵字:
?
- any
- all
?
子查詢結果集的形式:
?
-
- 單行單列(用于條件)
- 單行多列(用于條件)
- 多行單列(用于條件)
- 多行多列(用于表)
?
查詢學生生日在91年之后的班級的信息。
select * from classes where cid in (SELECT cno FROM student WHERE birthday > '1991-01-01');

帶exists的子查詢
?查詢學生生日大于91年1月1日,如果記錄存在,前面的SQL語句就會執行
select * from classes where exists (SELECT cno FROM student WHERE birthday > '1991-01-01');

帶any的子查詢
SELECT * FROM classes WHERE cid > ANY (SELECT cno FROM student )

帶all的子查詢
SELECT * FROM classes WHERE cid > ALL (SELECT cno FROM student)

?
事務
?
事務的特性(面試題)
?
原子性:指事務是一個不可分割的工作單位,事務中的操作要么都發生,要么都不發生。?
?
一致性:事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態。轉賬前和轉賬后的總金額不變。
?
隔離性:事務的隔離性是多個用戶并發訪問數據庫時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作數據所干擾,多個并發事務之間要相互隔離。
?
持久性:指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響。
?
?
?
4、事務的隔離級別
?
贓讀:指一個事務讀取了另一個事務未提交的數據。
?
不可重復讀:在一個事務內讀取表中的某一行數據,多次讀取結果不同。一個事務讀取到了另一個事務提交后的數據。(update)
?
虛讀(幻讀):是指在一個事務內讀取到了別的事務插入的數據,導致前后讀取不一致。 (insert)
?
?
?
數據庫通過設置事務的隔離級別防止以上情況的發生:
?
* 1、READ UNCOMMITTED: 贓讀、不可重復讀、虛讀都有可能發生。
?
* 2、READ COMMITTED: 避免贓讀。不可重復讀、虛讀都有可能發生。(oracle默認的)
?
* 4、REPEATABLE READ:避免贓讀、不可重復讀。虛讀有可能發生。(mysql默認)
?
* 8、SERIALIZABLE: 避免贓讀、不可重復讀、虛讀。
?
級別越高,性能越低,數據越安全
?
?
?
mysql中:
?
查看當前的事務隔離級別:SELECT @@TX_ISOLATION;
?
更改當前的事務隔離級別:SET TRANSACTION ISOLATION LEVEL 四個級別之一。
?
設置隔離級別必須在事務之前
?
?
?
練習:設置事務的隔離級別為 read uncommitted
?
時間 | 線程1 | 線程2 | 說明 |
t1 | begin; | ? | ? |
t2 | select * from account where name='zs'; 結果1000塊 | ? | ? |
t3 | ? | begin; | ? |
t4 | ? | update account set money=money+100 where name='zs'; | ? |
t5 | select * from account where name='zs'; 結果1100塊 | ? | 讀到了另一個線程未提交事務的數據。贓讀發生了 |
t6 | ? | commit; | ? |
t7 | select * from account where name='zs'; 結果1100塊 | ? | 讀到了另一個線程提交事務的update數據。不可重復讀發生了 |
t8 | ? | insert into account values(4,'zl',1000); 執行insert語句插入數據,事務自動提交了 | ? |
t9 | select * from account; 查到4條數據 | ? | 讀到了另一個線程自動提交事務的insert語句數據。虛讀發生了 |
t10 | commit; | ? | ? |
?