# 多表聯查
> 使用多表聯查的場景,有些時候數據在不同的表中,這個時候我們就需要用到mysql中的多表聯查。
## 多表聯查概念
> 將兩個或兩個以上的表按某個條件連接起來,從而選取需要的數據。多表聯查是同時查詢兩個或兩個以上的表時使用的。
## 多表聯查分類
1. 內連接查詢
內連接查詢使用關鍵字join或cross join 或 inner join,
然后通過on連接表與表之間的條件
注意: 內連接查詢只能查詢出兩個表符合條件的數據
語法:
SELECT 字段,字段1,..
FROM table_name1
INNER JOIN table_name2
ON table_name1.column_name=table_name2.column_name
2. 外連接查詢
2.1 左外連接
左外連接使用關鍵字left join,
然后通過on連接表與表之間的條件
注意:left join 會查詢出left join左邊的表所有的數據,即使右表沒有匹配
語法:
SELECT 字段,字段1,...
FROM table_name1
LEFT JOIN table_name2
ON table_name1.column_name=table_name2.column_name
2.2 右外連接
左外連接使用關鍵字right join,
然后通過on連接表與表之間的條件
注意: 即使左表中沒有匹配,也從右表返回所有的行
語法:
SELECT 字段,字段1,....
FROM table_name1
RIGHT JOIN table_name2
ON table_name1.column_name=table_name2.column_name
## 多表聯查例子
//用戶表
create table user(
id int primary key auto_increment,
name varchar(150) unique not null,
pass varchar(255) not null
)engine=innodb default charset=utf8;
//用戶詳情表
create table user_detail(
id int primary key auto_increment,
uid int not null comment '關聯用戶表的id',
city varchar(100) not null,
sex tinyint not null comment '1男 0女'
)engine=innodb default charset=utf8;
//訂單表
create table orders(
id int primary key auto_increment,
uid int not null comment '關聯用戶表的id',
orderno int not null comment '訂單號,關聯訂單詳情表id',
create_time timestamp not null comment '訂單下單時間'
)engine=innodb default charset=utf8;
//插入測試數據
insert into user(name,pass) values('jack',md5('123456'));
insert into user(name,pass) values('mary',md5('123456'));
insert into user(name,pass) values('rose',md5('123456'));
insert into user(name,pass) values('test',md5('123456'));
insert into user(name,pass) values('mark',md5('123456'));
insert into user_detail(uid,city,sex) values(1,'廣州',1);
insert into user_detail(uid,city,sex) values(2,'上海',0);
insert into user_detail(uid,city,sex) values(3,'北京',0);
insert into user_detail(uid,city,sex) values(4,'北京',1);
insert into orders(uid,orderno,create_time) values(2,3,now());
insert into orders(uid,orderno,create_time) values(4,5,now());
1. 查詢出用戶姓名,城市,性別
//實現方式一,這種方式等價於內連接
select user.id,name,city,sex from user,user_detail where user.id = user_detail.uid;
//實現方式二
select name,city,sex from user inner join user_detail on user.id=user_detail.uid;
//實現方式三
select name,city,sex from user join user_detail on user.id=user_detail.uid;
select name,city,sex from user cross join user_detail on user.id=user_detail.uid;
!!這幾種方式都是一樣的!!
2. 查詢出用戶的姓名,城市。並且性別為1的用戶
select name,city,sex from user inner join user_detail on user.id=user_detail.uid where sex=1;
3. 按照城市對用戶分組,得到每個城市的所有用戶名字
select group_concat(name) from user inner join user_detail on user.id=user_detail.uid group by city;
4. 按照城市對用戶分組,得到每個城市的所有用戶名字,並且只要組人數超過1個人的
select group_concat(name) from user inner join user_detail on user.id=user_detail.uid group by city having count(*) > 1;
5. 查詢出訂單表中的用戶的姓名,性別,城市,用戶id,以及用戶的下單時間(三表聯查)
已有什么,求什么?
已有uid,求姓名,性別,用戶下單時間
user表,user_detail,orders
select name,sex,city,u.id,create_time from orders as o inner join user as u on o.uid=u.id inner join user_detail d on u.id = d.uid;
* 外連接的實例
6. 列出所有用戶的所有信息(包括name,pass,sex,city)
//使用左連接實現
select u.id,name,pass,sex,city from user as u left join user_detail as d on u.id = d.uid;
//使用右連接實現
select u.id,name,pass,sex,city from user_detail as d right join user as u on u.id = d.uid;
# MySQL子查詢
* 子查詢定義
> 子查詢就是把一個查詢嵌套在另一個查詢中。
> 子查詢可以包含普通select可以包括任何子句,比如:distinct,group by, order by,limit,join等
* 注意
1. 子查詢先執行里面的SQL語句,再執行外面SQL語句。
2. 子查詢的效率比較低,一般建議使用join替換子查詢
3. 子查詢時,MySQL需要為內層查詢語句的查詢結果建立一個臨時表。然后外層查詢語句再臨時表中查詢記錄。查詢完畢后,MySQL需要撤銷這些臨時表。因此,子查詢的速度會受到一定的影響。如果查詢的數據量比較大,這種影響就會隨之增大。
* 使用子查詢原則
1. 一個子查詢必須放在圓括號中
2. 將子查詢放在比較條件的右邊,這樣可以增加SQL可讀性
## 子查詢分類
1. where 型子查詢(重點掌握)
where型子查詢把內層查詢結果當作外層查詢的比較條件
例如:
SELECT * FROM user WHERE id in (SELECT uid FROM user_detail );
2. exists/not exists型子查詢
EXISTS關鍵字表示存在。使用EXISTS關鍵字時,內層查詢語句不返回查詢的記錄,而是返回一個真假值,如果內層查詢語句查詢到滿足條件的記錄,只要子查詢中至少返回一個值,則EXISTS語句的值就為True。就返回true,否則返回false。當返回的值為true時,外層查詢語句將進行查詢,否則不進行查詢
3. 使用IN/NOT IN的子查詢
SELECT * FROM user WHERE id not in (SELECT uid FROM user_detail );
4. 使用比較運算符的子查詢 ( = > < >= <= != )
SELECT * FROM user WHERE id = (SELECT uid FROM user_detail limit 1 );
## 子查詢實例
//球員信息表
CREATE TABLE players(
playerno int NOT NULL comment '球員編號',
name CHAR(15) NOT NULL,
initials CHAR(3) NOT NULL comment '名字首字母',
birth_date DATE,
sex CHAR(1) NOT NULL,
joined SMALLINT NOT NULL comment '參入球隊年份',
street VARCHAR(30) NOT NULL comment '所在街道',
houseno CHAR(4) comment '房子編號',
postcode CHAR(6) comment '郵政編碼',
town VARCHAR(30) NOT NULL comment '小鎮名',
phoneno CHAR(13) comment '電話號碼',
leagueno CHAR(4) comment '在球隊中的號碼',
PRIMARY KEY (playerno)
)engine=innodb default charset=utf8;
//有過罰款記錄的球員信息表
CREATE TABLE penalties(
paymentno int NOT NULL,
playerno int NOT NULL comment '球員編號',
payment_date DATE NOT NULL comment '罰款時間',
amount DECIMAL(7,2) NOT NULL comment '罰款金額',
PRIMARY KEY (paymentno)
)engine=innodb default charset=utf8;
//插入測試數據
INSERT INTO players VALUES (2, 'Everett', 'R', '1948-09-01', 'M', 1975, 'Stoney Road','43', '3575NH', 'Stratford', '070-237893', '2411');
INSERT INTO players VALUES (6, 'Parmenter', 'R', '1964-06-25', 'M', 1977, 'Haseltine Lane','80', '1234KK', 'Stratford', '070-476537', '8467');
INSERT INTO players VALUES (7, 'Wise', 'GWS', '1963-05-11', 'M', 1981, 'Edgecombe Way','39', '9758VB', 'Stratford', '070-347689', NULL);
INSERT INTO players VALUES (8, 'Newcastle', 'B', '1962-07-08', 'F', 1980, 'Station Road','4', '6584WO', 'Inglewood', '070-458458', '2983');
INSERT INTO players VALUES (27, 'Collins', 'DD', '1964-12-28', 'F', 1983, 'Long Drive','804', '8457DK', 'Eltham', '079-234857', '2513');
INSERT INTO players VALUES (28, 'Collins', 'C', '1963-06-22', 'F', 1983, 'Old Main Road','10', '1294QK', 'Midhurst', '010-659599', NULL);
INSERT INTO players VALUES (39, 'Bishop', 'D', '1956-10-29', 'M', 1980, 'Eaton Square','78', '9629CD', 'Stratford', '070-393435', NULL);
INSERT INTO players VALUES (44, 'Baker', 'E', '1963-01-09', 'M', 1980, 'Lewis Street','23', '4444LJ', 'Inglewood', '070-368753', '1124');
INSERT INTO players VALUES (57, 'Brown', 'M', '1971-08-17', 'M', 1985, 'Edgecombe Way','16', '4377CB', 'Stratford', '070-473458', '6409');
INSERT INTO players VALUES (83, 'Hope', 'PK', '1956-11-11', 'M', 1982, 'Magdalene Road','16A', '1812UP', 'Stratford', '070-353548', '1608');
INSERT INTO players VALUES (95, 'Miller', 'P', '1963-05-14', 'M', 1972, 'High Street','33A', '5746OP', 'Douglas', '070-867564', NULL);
INSERT INTO players VALUES (100, 'Parmenter', 'P', '1963-02-28', 'M', 1979, 'Haseltine Lane','80', '6494SG', 'Stratford', '070-494593', '6524');
INSERT INTO players VALUES (104, 'Moorman', 'D', '1970-05-10', 'F', 1984, 'Stout Street','65', '9437AO', 'Eltham', '079-987571', '7060');
INSERT INTO players VALUES (112, 'Bailey', 'IP', '1963-10-01', 'F', 1984, 'Vixen Road','8', '6392LK', 'Plymouth', '010-548745', '1319');
INSERT INTO penalties VALUES (1, 6, '1980-12-08',100);
INSERT INTO penalties VALUES (2, 44, '1981-05-05', 75);
INSERT INTO penalties VALUES (3, 27, '1983-09-10',100);
INSERT INTO penalties VALUES (4,104, '1984-12-08', 50);
INSERT INTO penalties VALUES (5, 44, '1980-12-08', 25);
INSERT INTO penalties VALUES (6, 8, '1980-12-08', 25);
INSERT INTO penalties VALUES (7, 44, '1982-12-30', 30);
INSERT INTO penalties VALUES (8, 27, '1984-11-12', 75);
## 實例
2. 獲取和100號球員性別相同的球員號碼(where型子查詢)
select sex from players where playerno = 100;
select playerno from players where sex = 'M'
select playerno from players where sex = (select sex from players where playerno = 100)
3. 獲取和100號球員性別相同並且居住在同一城市的球員號碼。(where型子查詢)
select sex from players where playerno = 100;
select town from players where playerno = 100;
select playerno from players where sex = 'M' and city = 'Stratford';
select playerno from players where sex = (select sex from players where playerno = 100) and town = (select town from players where playerno = 100);
select playerno from players where (sex, town) = (
select sex, town from players where playerno = 100
);
4. 獲取到所有罰過款的球員信息(重點)
select playerno from penalties;//1,2,3,4
select * from players where playerno in (1,2,3,4);
select * from players where playerno in ( select playerno from penalties);
5. 獲取最老球員的號碼,名字及生日。(即出生日期數值小於或等於所有其它球員的球員)
select playerno, name, birth_date from players where birth_date <= all
(select birth_date from players);
6. 查詢出被罰款超過50的球員名字與電話
select name, phoneno from players where playerno in ( select playerno from penalties where amount > 50);