给定一个 salary 表,如下所示,有 m = 男性 和 f = 女性 的值。交换所有的 f 和 m 值(例如,将所有 f 值更改为 m,反之亦然)。要求只使用一个更新(Update)语句,并且没有中间的临时表。
注意,您必只能写一个 Update 语句,请不要编写任何 Select 语句。
update salary set sex = IF(sex = 'm', 'f', 'm')
可以使用 if 函数判断 列的值 进行数据交换 当没有where 条件的时候会更新全表
IF 函数用法
IF(expr,v1,v2) 如果表达式 expr 成立,返回结果 v1;否则,返回结果 v2
编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary)。
方法1:将 Salary 去重后降序排列,再返回第二条记录可得第二大的值
也许只有一个 Salary 值,将返回 null
select (select distinct Salary from Employee limit 1,1) as secondhighestsalary;
方法2:找出小于该字段最大值的最大值,即为第二大值
select MAX(Salary) as secondhighestsalary from Employee
where Salary <(select MAX(Salary) from Employee );
limit N # 返回 N 条记录
offset M # 跳过 M 条记录,M 默认为 0
limit M,N # 相当于 limit N offset M,从第 M 条记录开始,返回 N 条记录
查找薪水涨幅超过15次的员工号emp_no以及其对应的涨幅次数t
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
select emp_no, count(emp_no)as t from salaries
group by emp_no having t>15;
此题应注意以下四点:
1、用COUNT()函数和GROUP BY语句可以统计同一emp_no值的记录条数
2、根据题意,输出的涨幅次数为t,故用AS语句将COUNT(emp_no)的值转换为t
3、由于COUNT()函数不可用于WHERE语句中,故使用HAVING语句来限定t>15的条件 4、最后存在一个理解误区,涨幅超过15次,salaries中相应的记录数应该超过16(从第2条记录开始算作第1次涨幅),不过题目为了简单起见,将第1条记录当作第1次涨幅,所以令t>15即可
注意: 严格来说,下一条salary高于本条才算涨幅,但本题只要出现了一条记录就算一次涨幅,salary相同可以理解为涨幅为0,salary变少理解为涨幅为负
此题应该是默认每次变化都是增长且不重复的。
找出所有员工当前(to_date=‘9999-01-01’)具体的薪水salary情况,对于相同的薪水只显示一次,并按照逆序显示
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
方法1:适用小表
select distinct salary from salaries
where to_date='9999-01-01' order by salary desc
方法2:适用大表
select salary from salaries
where to_date='9999-01-01' group by salary
order by salary desc
1.大表一般用distinct效率不高,大数据量的时候都禁止用distinct,建议用group by解决重复问题
2.WHERE语句在GROUP BY语句之前,SQL会在分组之前计算WHERE语句。
HAVING语句在GROUP BY语句之后,SQL会在分组之后计算HAVING语句
having 是过滤组 where过滤行
需增强order by 语句
获取所有部门当前manager的当前薪水情况,给出dept_no, emp_no以及salary,当前表示to_date=‘9999-01-01’
CREATE TABLE dept_manager
(
dept_no
char(4) NOT NULL,
emp_no
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
select d.dept_no,d.emp_no,s.salary
from salaries as s inner join dept_manager as d
on s.emp_no = d.emp_no
and s.to_date='9999-01-01'
and d.to_date='9999-01-01'
select dept_no,emp_no,salary from dept_manager
where to_date='9999-01-01'
from salaries inner join dept_manager
on salaries.emp_no = dept_manager.emp_no
先联结再where
获取所有非manager的员工emp_no
CREATE TABLE dept_manager
(
dept_no
char(4) NOT NULL,
emp_no
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE employees
(
emp_no
int(11) NOT NULL,
birth_date
date NOT NULL,
first_name
varchar(14) NOT NULL,
last_name
varchar(16) NOT NULL,
gender
char(1) NOT NULL,
hire_date
date NOT NULL,
PRIMARY KEY (emp_no
));
方法一:先使用LEFT JOIN连接两张表,再从此表中选出dept_no值为NULL对应的emp_no记录
select employees.emp_no from employees
left join dept_manager
on employees.emp_no = dept_manager.emp_no
where dept_no is null;
方法二:使用NOT IN选出在employees但不在dept_manager中的emp_no记录
select emp_no from employees
where emp_no not in (
select emp_no from dept_manager)
寻找空值的语句为:where dept_no is null
获取所有员工当前的manager,如果当前的manager是自己的话结果不显示,当前表示to_date=‘9999-01-01’。
结果第一列给出当前员工的emp_no,第二列给出其manager对应的manager_no。
CREATE TABLE dept_emp
(
emp_no
int(11) NOT NULL,
dept_no
char(4) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE dept_manager
(
dept_no
char(4) NOT NULL,
emp_no
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
select de.emp_no,dm.emp_no AS manager_no
from dept_manager AS dm,dept_emp AS de
where de.emp_no <> dm.emp_no
and de.dept_no = dm.dept_no
and dm.to_date='9999-01-01';
1.因为要输出自己的经理,得知自己与经理的部门要相同,故有限制条件 de.dept_no = dm.dept_no
2.select… from …where…可以直接连接表
3.为了增强代码可读性,将 dept_emp 用别名 de 代替,dept_manager 用 dm 代替
对应的salary
CREATE TABLE dept_emp
(
emp_no
int(11) NOT NULL,
dept_no
char(4) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
select d.dept_no, s.emp_no, max(s.salary)
from dept_emp as d,salaries as s
where d.emp_no = s.emp_no
and d.to_date = '9999-01-01'
and s.to_date = '9999-01-01'
group by dept_no
1.先用INNER JOIN连接两张表,限制条件是两张表的emp_no相同,即d.emp_no = s.emp_no;
2.用GROUP BY d.dept_no将每个部门分为一组,用MAX()函数选取每组中工资最高者
题目描述
从titles表获取按照title进行分组,每组个数大于等于2,给出title以及对应的数目t。
注意对于重复的emp_no进行忽略。
CREATE TABLE IF NOT EXISTS titles
(
emp_no
int(11) NOT NULL,
title
varchar(50) NOT NULL,
from_date
date NOT NULL,
to_date
date DEFAULT NULL);
方法一
select title ,count(distinct emp_no) as t
from titles
group by title
having t>=2
方法二
select title,count(title) as tfrom (select distinct emp_no,title,from_date,to_date from titles )group by title having t>=2;
本题中,title的数=emp_no=记录数吗?
题目描述
查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列
CREATE TABLE employees
(
emp_no
int(11) NOT NULL,
birth_date
date NOT NULL,
first_name
varchar(14) NOT NULL,
last_name
varchar(16) NOT NULL,
gender
char(1) NOT NULL,
hire_date
date NOT NULL,
PRIMARY KEY (emp_no
))
select * from employees
where emp_no % 2 =1
and last_name != 'Mary'
order by hire_date desc
三点需要注意:
1、员工号为奇数,则emp_no取余(%)应为1
2、last_name不为Mary,Mary 要用’’,用‘!=’或‘<>’表示
3. 根据hire_date逆序排列,用desc
题目描述
统计出当前各个title类型对应的员工当前(to_date=‘9999-01-01’)薪水对应的平均工资。结果给出title以及平均工资avg。
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
CREATE TABLE IF NOT EXISTS “titles” (
emp_no
int(11) NOT NULL,
title
varchar(50) NOT NULL,
from_date
date NOT NULL,
to_date
date DEFAULT NULL);
select title ,avg(salary) as avg
from titles a inner join salaries b
on a.emp_no= b.emp_no and a.to_date= '9999-01-01' and b.to_date = '9999-01-01'
group by a.title
查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
CREATE TABLE departments
(
dept_no
char(4) NOT NULL,
dept_name
varchar(40) NOT NULL,
PRIMARY KEY (dept_no
));
CREATE TABLE dept_emp
(
emp_no
int(11) NOT NULL,
dept_no
char(4) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE employees
(
emp_no
int(11) NOT NULL,
birth_date
date NOT NULL,
SELECT last_name,first_name,de.dept_name
from employees as e
left join dept_emp as d on e.emp_no =d.emp_no
left join departments as de on d.dept_no =de.dept_no
本题思路为运用两次LEFT JOIN连接嵌套
1、第一次LEFT JOIN连接employees表与dept_emp表,得到所有员工的last_name和first_name以及对应的dept_no,也包括暂时没有分配部门的员工
2、第二次LEFT JOIN连接上表与departments表,即连接dept_no与dept_name,得到所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工
查找员工编号emp_no为10001其自入职以来的薪水salary涨幅值growth
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
select
( select salary from salaries where emp_no = 10001
order by to_date desc limit 1)
-
( select salary from salaries where emp_no = 10001
order by to_date asc limit 1) as growth
1、先分别找到emp_no=10001的员工的第一次工资记录与最后一次工资记录
2、再将最后一次工资记录减去第一次工资记录得到入职以来salary的涨幅,最后用别名growth代替
查找所有员工自入职以来的薪水涨幅情况,给出员工编号emp_no以及其对应的薪水涨幅growth,并按照growth进行升序
CREATE TABLE employees
(
emp_no
int(11) NOT NULL,
birth_date
date NOT NULL,
first_name
varchar(14) NOT NULL,
last_name
varchar(16) NOT NULL,
gender
char(1) NOT NULL,
hire_date
date NOT NULL,
PRIMARY KEY (emp_no
));
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
select a.emp_no, (b.salary - c.salary) as growth
from
employees as a
inner join salaries as b
on a.emp_no=b.emp_no and b.to_date ='9999-01-01'
inner join salaries as c
on a.emp_no=c.emp_no where a.hire_date = c.from_date
order by growth asc
1.同个表可重复联结,选定不同的日期相减
2.注意on后的条件用“and”连接而不是“where”
统计各个部门的工资记录数,给出部门编码dept_no、部门名称dept_name以及次数sum
CREATE TABLE departments
(
dept_no
char(4) NOT NULL,
dept_name
varchar(40) NOT NULL,
PRIMARY KEY (dept_no
));
CREATE TABLE dept_emp
(
emp_no
int(11) NOT NULL,
dept_no
char(4) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
select de.dept_no,de.dept_name, count(s.salary) as sum
from departments as de ,dept_emp as d ,salaries as s
where de.dept_no =d.dept_no
and d.emp_no = s.emp_no
group by d.dept_no
此处为什么用全连接。
题目描述
对所有员工的当前(to_date=‘9999-01-01’)薪水按照salary进行按照1-N的排名,相同salary并列且按照emp_no升序排列
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
select s1.emp_no,s1.salary ,count( distinct s2.salary) as rank
from salaries as s1,salaries as s2
WHERE s1.to_date='9999-01-01'
and s2.to_date='9999-01-01'
and s1.salary<= s2.salary
group by s1.emp_no
order by s1.salary desc,s1.emp_no asc
本题的主要思想是复用salaries表进行比较排名,具体思路如下:
1、从两张相同的salaries表(分别为s1与s2)进行对比分析,先将两表限定条件设为to_date = ‘9999-01-01’,挑选出当前所有员工的薪水情况。
2、本题的精髓在于 s1.salary <= s2.salary,意思是在输出s1.salary的情况下,有多少个s2.salary大于等于1.salary,比如当s1.salary=94409时,有3个s2.salary(分别为94692,94409,94409)大于等于它,但由于94409重复,利用COUNT(DISTINCT s2.salary)去重可得工资为94409的rank等于2。其余排名以此类推。
3、千万不要忘了GROUP BY s1.emp_no,否则输出的记录只有一条(可能是第一条或者最后一条,根据不同的数据库而定),因为用了合计函数COUNT()
4、最后先以 s1.salary 逆序排列,再以 s1.emp_no 顺序排列输出结果
获取所有非manager员工当前的薪水情况,给出dept_no、emp_no以及salary ,当前表示to_date=‘9999-01-01’
CREATE TABLE dept_emp
(
emp_no
int(11) NOT NULL,
dept_no
char(4) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE dept_manager
(
dept_no
char(4) NOT NULL,
emp_no
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE employees
(
emp_no
int(11) NOT NULL,
birth_date
date NOT NULL,
first_name
varchar(14) NOT NULL,
last_name
varchar(16) NOT NULL,
gender
char(1) NOT NULL,
hire_date
date NOT NULL,
PRIMARY KEY (emp_no
));
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
select de.dept_no,s.emp_no,s.salary
from employees as e
inner join salaries as s on e.emp_no = s.emp_no and s.to_date='9999-01-01'
inner join dept_emp as de on e.emp_no = de.emp_no
where de.emp_no not in (
select emp_no from dept_manager where to_date='9999-01-01')
1、先用INNER JOIN连接employees和salaries,找出当前所有员工的工资情况
2、再用INNER JOIN连接dept_emp表,找到所有员工所在的部门
3、最后用限制条件de.emp_no NOT IN (SELECT emp_no FROM dept_manager WHERE to_date = ‘9999-01-01’)选出当前所有非manager员工,再依次输出dept_no、emp_no、salary
1.on 后面可以加and还是where?
2.主键的连接,如何判断连接一个还是两个?
(从这里开始觉得好难,没思路,哭晕在厕所,但素!坚持住~)
获取员工其当前的薪水比其manager当前薪水还高的相关信息,当前表示to_date=‘9999-01-01’,
结果第一列给出员工的emp_no,
第二列给出其manager的manager_no,
第三列给出该员工当前的薪水emp_salary,
第四列给该员工对应的manager当前的薪水manager_salary
CREATE TABLE dept_emp
(
emp_no
int(11) NOT NULL,
dept_no
char(4) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE dept_manager
(
dept_no
char(4) NOT NULL,
emp_no
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE salaries
(
emp_no
int(11) NOT NULL,
salary
int(11) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,from_date
));
1.把问题拆分成小表,获取小表后再进一步提取得到大表,由主键找表的连接方式。
2.“获取员工其当前的薪水比其manager当前薪水还高”需要两个薪水表:员工和经理
因此:
(1)先用INNER JOIN连接salaries和demp_emp,建立员工的工资记录
(2)再用INNER JOIN连接salaries和demp_manager,建立经理的工资记录
3. 最后用限制条件s1.dept_no = s2.dept_no AND s1.salary > s2.salary找出同一部门中工资比经理高的员工,并根据题意依次输出emp_no、manager_no、emp_salary、manager_salary
select s1.emp_no as emp_no,s2.emp_no as manager_no,s1.salary as emp_salary,s2.salary as manager_salary
from(
select s.emp_no,s.salary,de.dept_no
from dept_emp as de inner join salaries as s
on de.emp_no = s.emp_no
and s.to_date='9999-01-01' ) as s1,
(select s.emp_no,s.salary,dm.dept_no
from dept_manager as dm inner join salaries as s
on dm.emp_no = s.emp_no
and s.to_date='9999-01-01' ) as s2
where s1.dept_no =s2.dept_no
and s1.salary > s2.salary
汇总各个部门当前员工的title类型的分配数目,结果给出部门编号dept_no、dept_name、其当前员工所有的title以及该类型title对应的数目count
CREATE TABLE departments
(
dept_no
char(4) NOT NULL,
dept_name
varchar(40) NOT NULL,
PRIMARY KEY (dept_no
));
CREATE TABLE dept_emp
(
emp_no
int(11) NOT NULL,
dept_no
char(4) NOT NULL,
from_date
date NOT NULL,
to_date
date NOT NULL,
PRIMARY KEY (emp_no
,dept_no
));
CREATE TABLE IF NOT EXISTS titles
(
emp_no
int(11) NOT NULL,
title
varchar(50) NOT NULL,
from_date
date NOT NULL,
to_date
date DEFAULT NULL);
select de.dept_no ,de.dept_name ,
t.title ,count(t.title) as count
from dept_emp em inner join departments de
on de.dept_no = em.dept_no
and em.to_date='9999-01-01'
inner join titles t
on em.emp_no = t.emp_no
and t.to_date='9999-01-01'
group by de.dept_no,t.title
本题的关键在于用 GROUP BY 同时对 de.dept_no 和 t.title 进行分组,具体思路如下:
1、先用 INNER JOIN 连接 dept_emp 与 salaries,根据测试数据添加限定条件 de.to_date = ‘9999-01-01’ AND t.to_date = ‘9999-01-01’,即当前员工的当前头衔
2、再用 INNER JOIN 连接departments,限定条件为 de.dept_no = dp.dept_no,即部门编号相同
3、最后用 GROUP BY 同时对 de.dept_no 和 t.title 进行分组,用 COUNT(t.title) 统计相同部门下相同头衔的员工个数