目錄mysql
建表與數據準備:sql
# 建表 create table department( id int, name varchar(20) ); create table employee( id int primary key auto_increment, name varchar(20), sex enum('male','female') not null default 'male', age int, dep_id int ); # 插入數據 insert into department values (200,'技術'), (201,'人力資源'), (202,'銷售'), (203,'運營'); insert into employee(name,sex,age,dep_id) values ('nick','male',18,200), ('jason','female',48,201), ('sean','male',38,201), ('tank','female',28,202), ('oscar','male',18,200), ('mac','female',18,204) ; # 查看錶結構和數據 mysql> desc department; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ mysql> desc employee; +--------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | YES | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(11) | YES | | NULL | | | dep_id | int(11) | YES | | NULL | | +--------+-----------------------+------+-----+---------+----------------+ mysql> select * from department; +------+--------------+ | id | name | +------+--------------+ | 200 | 技術 | | 201 | 人力資源 | | 202 | 銷售 | | 203 | 運營 | +------+--------------+ mysql> select * from employee; +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | nick | male | 18 | 200 | | 2 | jason | female | 48 | 201 | | 3 | sean | male | 38 | 201 | | 4 | tank | female | 28 | 202 | | 5 | oscar | male | 18 | 200 | | 6 | mac | female | 18 | 204 | +----+------------+--------+------+--------+ 表department與employee
重點:外連接語法windows
SELECT 字段列表 FROM 表1 INNER|LEFT|RIGHT JOIN 表2 ON 表1.字段 = 表2.字段;
不適用任何匹配條件。生成笛卡爾積post
mysql> select * from employee,department; +----+------------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +----+------------+--------+------+--------+------+--------------+ | 1 | nick | male | 18 | 200 | 200 | 技術 | | 1 | nick | male | 18 | 200 | 201 | 人力資源 | | 1 | nick | male | 18 | 200 | 202 | 銷售 | | 1 | nick | male | 18 | 200 | 203 | 運營 | | 2 | jason | female | 48 | 201 | 200 | 技術 | | 2 | jason | female | 48 | 201 | 201 | 人力資源 | | 2 | jason | female | 48 | 201 | 202 | 銷售 | | 2 | jason | female | 48 | 201 | 203 | 運營 | | 3 | sean | male | 38 | 201 | 200 | 技術 | | 3 | sean | male | 38 | 201 | 201 | 人力資源 | | 3 | sean | male | 38 | 201 | 202 | 銷售 | | 3 | sean | male | 38 | 201 | 203 | 運營 | | 4 | tank | female | 28 | 202 | 200 | 技術 | | 4 | tank | female | 28 | 202 | 201 | 人力資源 | | 4 | tank | female | 28 | 202 | 202 | 銷售 | | 4 | tank | female | 28 | 202 | 203 | 運營 | | 5 | oscar | male | 18 | 200 | 200 | 技術 | | 5 | oscar | male | 18 | 200 | 201 | 人力資源 | | 5 | oscar | male | 18 | 200 | 202 | 銷售 | | 5 | oscar | male | 18 | 200 | 203 | 運營 | | 6 | mac | female | 18 | 204 | 200 | 技術 | | 6 | mac | female | 18 | 204 | 201 | 人力資源 | | 6 | mac | female | 18 | 204 | 202 | 銷售 | | 6 | mac | female | 18 | 204 | 203 | 運營 | +----+------------+--------+------+--------+------+--------------+
只鏈接匹配的行學習
# 找兩張表共有的部分,至關於利用條件從笛卡爾積結果中篩選出了正確的結果 # department沒有204這個部門,於是employee表中關於204這條員工信息沒有匹配出來 mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee inner join department on employee.dep_id=department.id; +----+-----------+------+--------+--------------+ | id | name | age | sex | name | +----+-----------+------+--------+--------------+ | 1 | nick | 18 | male | 技術 | | 2 | jason | 48 | female | 人力資源 | | 3 | sean | 38 | male | 人力資源 | | 4 | tank | 28 | female | 銷售 | | 5 | oscar | 18 | male | 技術 | +----+-----------+------+--------+--------------+ # 上述sql等同於 mysql> select employee.id,employee.name,employee.age,employee.sex,department.name from employee,department where employee.dep_id=department.id;
優先顯示左表所有記錄網站
# 以左表爲準,即找出全部員工信息,固然包括沒有部門的員工 # 本質就是:在內鏈接的基礎上增長左邊有右邊沒有的結果 mysql> select employee.id,employee.name,department.name as depart_name from employee left join department on employee.dep_id=department.id; +----+------------+--------------+ | id | name | depart_name | +----+------------+--------------+ | 1 | nick | 技術 | | 5 | oscar | 技術 | | 2 | jason | 人力資源 | | 3 | sean | 人力資源 | | 4 | tank | 銷售 | | 6 | mac | NULL | +----+------------+--------------+
優先顯示右表所有記錄編碼
# 以右表爲準,即找出全部部門信息,包括沒有員工的部門 # 本質就是:在內鏈接的基礎上增長右邊有左邊沒有的結果 mysql> select employee.id,employee.name,department.name as depart_name from employee right join department on employee.dep_id=department.id; +------+-----------+--------------+ | id | name | depart_name | +------+-----------+--------------+ | 1 | nick | 技術 | | 2 | jason | 人力資源 | | 3 | sean | 人力資源 | | 4 | tank | 銷售 | | 5 | oscar | 技術 | | NULL | NULL | 運營 | +------+-----------+--------------+
顯示左右兩個表所有記錄code
全外鏈接:在內鏈接的基礎上增長左邊有右邊沒有的和右邊有左邊沒有的結果 # 注意:mysql不支持全外鏈接 full JOIN # 強調:mysql可使用此種方式間接實現全外鏈接 select * from employee left join department on employee.dep_id = department.id union select * from employee right join department on employee.dep_id = department.id ; # 查看結果 +------+------------+--------+------+--------+------+--------------+ | id | name | sex | age | dep_id | id | name | +------+------------+--------+------+--------+------+--------------+ | 1 | nick | male | 18 | 200 | 200 | 技術 | | 5 | oscar | male | 18 | 200 | 200 | 技術 | | 2 | jason | female | 48 | 201 | 201 | 人力資源 | | 3 | sean | male | 38 | 201 | 201 | 人力資源 | | 4 | tank | female | 28 | 202 | 202 | 銷售 | | 6 | mac | female | 18 | 204 | NULL | NULL | | NULL | NULL | NULL | NULL | NULL | 203 | 運營 | +------+------------+--------+------+--------+------+--------------+ # 注意 union與union all的區別:union會去掉相同的紀錄
# 示例1:之內鏈接的方式查詢employee和department表,而且employee表中的age字段值必須大於25,即找出年齡大於25歲的員工以及員工所在的部門 select employee.name,department.name from employee inner join department on employee.dep_id = department.id where age > 25; # 示例2:之內鏈接的方式查詢employee和department表,而且以age字段的升序方式顯示 select employee.id,employee.name,employee.age,department.name from employee,department where employee.dep_id = department.id and age > 25 order by age asc;
# 查詢平均年齡在25歲以上的部門名 select id,name from department where id in (select dep_id from employee group by dep_id having avg(age) > 25); # 查看技術部員工姓名 select name from employee where dep_id in (select id from department where name='技術'); # 查看不足1人的部門名(子查詢獲得的是有人的部門id) select name from department where id not in (select distinct dep_id from employee);
# 比較運算符:=、!=、>、>=、<、<=、<> # 查詢大於全部人平均年齡的員工名與年齡 mysql> select name,age from emp where age > (select avg(age) from emp); +---------+------+ | name | age | +---------+------+ | jason | 48 | | sean | 38 | +---------+------+ rows in set (0.00 sec) # 查詢大於部門內平均年齡的員工名、年齡 select t1.name,t1.age from emp t1 inner join (select dep_id,avg(age) avg_age from emp group by dep_id) t2 on t1.dep_id = t2.dep_id where t1.age > t2.avg_age;
EXISTS關字鍵字表示存在。在使用EXISTS關鍵字時,內層查詢語句不返回查詢的記錄。blog
而是返回一個真假值。True或Falseutf-8
當返回True時,外層查詢語句將進行查詢;當返回值爲False時,外層查詢語句不進行查詢。
# department表中存在dept_id=203,Ture mysql> select * from employee -> where exists -> (select id from department where id=200); +----+------------+--------+------+--------+ | id | name | sex | age | dep_id | +----+------------+--------+------+--------+ | 1 | nick | male | 18 | 200 | | 2 | jason | female | 48 | 201 | | 3 | sean | male | 38 | 201 | | 4 | tank | female | 28 | 202 | | 5 | oscar | male | 18 | 200 | | 6 | mac | female | 18 | 204 | +----+------------+--------+------+--------+ # department表中存在dept_id=205,False mysql> select * from employee -> where exists -> (select id from department where id=204); Empty set (0.00 sec)
company.employee 員工id id int 姓名 emp_name varchar 性別 sex enum 年齡 age int 入職日期 hire_date date 崗位 post varchar 職位描述 post_comment varchar 薪水 salary double 辦公室 office int 部門編號 depart_id int # 建立表 create table employee( id int not null unique auto_increment, name varchar(20) not null, sex enum('male','female') not null default 'male', # 大部分是男的 age int(3) unsigned not null default 28, hire_date date not null, post varchar(50), post_comment varchar(100), salary double(15,2), office int, # 一個部門一個屋子 depart_id int ); # 查看錶結構 mysql> desc employee; +--------------+-----------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-----------------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | sex | enum('male','female') | NO | | male | | | age | int(3) unsigned | NO | | 28 | | | hire_date | date | NO | | NULL | | | post | varchar(50) | YES | | NULL | | | post_comment | varchar(100) | YES | | NULL | | | salary | double(15,2) | YES | | NULL | | | office | int(11) | YES | | NULL | | | depart_id | int(11) | YES | | NULL | | +--------------+-----------------------+------+-----+---------+----------------+ # 插入記錄 # 三個部門:教學,銷售,運營 insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values ('nick','male',18,'20170301','老男孩上海虹橋最帥',7300.33,401,1), # 如下是教學部 ('jason','male',78,'20150302','teacher',1000000.31,401,1), ('sean','male',81,'20130305','teacher',8300,401,1), ('tank','male',73,'20140701','teacher',3500,401,1), ('oscar','male',28,'20121101','teacher',2100,401,1), ('mac','female',18,'20110211','teacher',9000,401,1), ('rocky','male',18,'19000301','teacher',30000,401,1), ('成龍','male',48,'20101111','teacher',10000,401,1), ('歪歪','female',48,'20150311','sale',3000.13,402,2),# 如下是銷售部門 ('丫丫','female',38,'20101101','sale',2000.35,402,2), ('丁丁','female',18,'20110312','sale',1000.37,402,2), ('星星','female',18,'20160513','sale',3000.29,402,2), ('格格','female',28,'20170127','sale',4000.33,402,2), ('張野','male',28,'20160311','operation',10000.13,403,3), # 如下是運營部門 ('程咬金','male',18,'19970312','operation',20000,403,3), ('程咬銀','female',18,'20130311','operation',19000,403,3), ('程咬銅','male',18,'20150411','operation',18000,403,3), ('程咬鐵','female',18,'20140512','operation',17000,403,3) ; # ps:若是在windows系統中,插入中文字符,select的結果爲空白,能夠將全部字符編碼統一設置成gbk
SELECT * FROM emp AS t1 INNER JOIN ( SELECT post, max(hire_date) max_date FROM emp GROUP BY post ) AS t2 ON t1.post = t2.post WHERE t1.hire_date = t2.max_date;
mysql> select (select t2.name from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) from emp as t1 group by post; +---------------------------------------------------------------------------------------+ | (select t2.name from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) | +---------------------------------------------------------------------------------------+ | 張野 | | 格格 | | jason | | nick | +---------------------------------------------------------------------------------------+ rows in set (0.00 sec) mysql> select (select t2.id from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) from emp as t1 group by post; +-------------------------------------------------------------------------------------+ | (select t2.id from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) | +-------------------------------------------------------------------------------------+ | 14 | | 13 | | 2 | | 1 | +-------------------------------------------------------------------------------------+ rows in set (0.00 sec) # 正確答案 mysql> select t3.name,t3.post,t3.hire_date from emp as t3 where id in (select (select id from emp as t2 where t2.post=t1.post order by hire_date desc limit 1) from emp as t1 group by post); +--------+-----------------------------------------+------------+ | name | post | hire_date | +--------+-----------------------------------------+------------+ | nick | 老男孩上海虹橋最帥 | 2017-03-01 | | jason | teacher | 2015-03-02 | | 格格 | sale | 2017-01-27 | | 張野 | operation | 2016-03-11 | +--------+-----------------------------------------+------------+ rows in set (0.00 sec)
答案一爲正確答案,答案二中的limit 1有問題(每一個部門可能有>1個爲同一時間入職的新員工),我只是想用該例子來講明能夠在select後使用子查詢。
能夠基於上述方法解決:好比某網站在全國各個市都有站點,每一個站點一條數據,想取每一個省下最新的那一條市的網站質量信息。
/* 數據導入: Navicat Premium Data Transfer Source Server : localhost Source Server Type : MySQL Source Server Version : 50624 Source Host : localhost Source Database : sqlexam Target Server Type : MySQL Target Server Version : 50624 File Encoding : utf-8 Date: 10/21/2016 06:46:46 AM */ SET NAMES utf8; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `class` -- ---------------------------- DROP TABLE IF EXISTS `class`; CREATE TABLE `class` ( `cid` int(11) NOT NULL AUTO_INCREMENT, `caption` varchar(32) NOT NULL, PRIMARY KEY (`cid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `class` -- ---------------------------- BEGIN; INSERT INTO `class` VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班'); COMMIT; -- ---------------------------- -- Table structure for `course` -- ---------------------------- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `cid` int(11) NOT NULL AUTO_INCREMENT, `cname` varchar(32) NOT NULL, `teacher_id` int(11) NOT NULL, PRIMARY KEY (`cid`), KEY `fk_course_teacher` (`teacher_id`), CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `course` -- ---------------------------- BEGIN; INSERT INTO `course` VALUES ('1', '生物', '1'), ('2', '物理', '2'), ('3', '體育', '3'), ('4', '美術', '2'); COMMIT; -- ---------------------------- -- Table structure for `score` -- ---------------------------- DROP TABLE IF EXISTS `score`; CREATE TABLE `score` ( `sid` int(11) NOT NULL AUTO_INCREMENT, `student_id` int(11) NOT NULL, `course_id` int(11) NOT NULL, `num` int(11) NOT NULL, PRIMARY KEY (`sid`), KEY `fk_score_student` (`student_id`), KEY `fk_score_course` (`course_id`), CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`), CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`) ) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `score` -- ---------------------------- BEGIN; INSERT INTO `score` VALUES ('1', '1', '1', '10'), ('2', '1', '2', '9'), ('5', '1', '4', '66'), ('6', '2', '1', '8'), ('8', '2', '3', '68'), ('9', '2', '4', '99'), ('10', '3', '1', '77'), ('11', '3', '2', '66'), ('12', '3', '3', '87'), ('13', '3', '4', '99'), ('14', '4', '1', '79'), ('15', '4', '2', '11'), ('16', '4', '3', '67'), ('17', '4', '4', '100'), ('18', '5', '1', '79'), ('19', '5', '2', '11'), ('20', '5', '3', '67'), ('21', '5', '4', '100'), ('22', '6', '1', '9'), ('23', '6', '2', '100'), ('24', '6', '3', '67'), ('25', '6', '4', '100'), ('26', '7', '1', '9'), ('27', '7', '2', '100'), ('28', '7', '3', '67'), ('29', '7', '4', '88'), ('30', '8', '1', '9'), ('31', '8', '2', '100'), ('32', '8', '3', '67'), ('33', '8', '4', '88'), ('34', '9', '1', '91'), ('35', '9', '2', '88'), ('36', '9', '3', '67'), ('37', '9', '4', '22'), ('38', '10', '1', '90'), ('39', '10', '2', '77'), ('40', '10', '3', '43'), ('41', '10', '4', '87'), ('42', '11', '1', '90'), ('43', '11', '2', '77'), ('44', '11', '3', '43'), ('45', '11', '4', '87'), ('46', '12', '1', '90'), ('47', '12', '2', '77'), ('48', '12', '3', '43'), ('49', '12', '4', '87'), ('52', '13', '3', '87'); COMMIT; -- ---------------------------- -- Table structure for `student` -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `sid` int(11) NOT NULL AUTO_INCREMENT, `gender` char(1) NOT NULL, `class_id` int(11) NOT NULL, `sname` varchar(32) NOT NULL, PRIMARY KEY (`sid`), KEY `fk_class` (`class_id`), CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`) ) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `student` -- ---------------------------- BEGIN; INSERT INTO `student` VALUES ('1', '男', '1', '理解'), ('2', '女', '1', '鋼蛋'), ('3', '男', '1', '張三'), ('4', '男', '1', '張一'), ('5', '女', '1', '張二'), ('6', '男', '1', '張四'), ('7', '女', '2', '鐵錘'), ('8', '男', '2', '李三'), ('9', '男', '2', '李一'), ('10', '女', '2', '李二'), ('11', '男', '2', '李四'), ('12', '女', '3', '如花'), ('13', '男', '3', '劉三'), ('14', '男', '3', '劉一'), ('15', '女', '3', '劉二'), ('16', '男', '3', '劉四'); COMMIT; -- ---------------------------- -- Table structure for `teacher` -- ---------------------------- DROP TABLE IF EXISTS `teacher`; CREATE TABLE `teacher` ( `tid` int(11) NOT NULL AUTO_INCREMENT, `tname` varchar(32) NOT NULL, PRIMARY KEY (`tid`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of `teacher` -- ---------------------------- BEGIN; INSERT INTO `teacher` VALUES ('1', '張磊老師'), ('2', '李平老師'), ('3', '劉海燕老師'), ('4', '朱雲海老師'), ('5', '李傑老師'); COMMIT; SET FOREIGN_KEY_CHECKS = 1;
# 準備表、記錄 mysql> create database db1; mysql> use db1; mysql> source /root/init.sql
查詢男生、女生的人數;
查詢姓「張」的學生名單;
課程平均分從高到低顯示
查詢有課程成績小於60分的同窗的學號、姓名;
查詢至少有一門課與學號爲1的同窗所學課程相同的同窗的學號和姓名;
查詢出只選修了一門課程的所有學生的學號和姓名;
查詢各科成績最高和最低的分:以以下形式顯示:課程ID,最高分,最低分;
查詢課程編號「2」的成績比課程編號「1」課程低的全部同窗的學號、姓名;
查詢「生物」課程比「物理」課程成績高的全部學生的學號;
查詢平均成績大於60分的同窗的學號和平均成績;
查詢全部同窗的學號、姓名、選課數、總成績;
查詢姓「李」的老師的個數;
查詢沒學過「張磊老師」課的同窗的學號、姓名;
查詢學過「1」而且也學過編號「2」課程的同窗的學號、姓名;
查詢學過「李平老師」所教的全部課的同窗的學號、姓名;