目录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”课程的同窗的学号、姓名;
查询学过“李平老师”所教的全部课的同窗的学号、姓名;