1. not in
用一条 SQL 语句,查询出每门课程都大于 80 分的人。
分析:
- 去重查询出存在课程小于 80 分的人,设为集合A
- 查询不在集合 A 中的人
# 第一步:找小于等于80分的学员姓名
select distinct name from t_student where fenshu <= 80# 第二步:not in
select distinct name from t_student where name not in(select distinct name from t_student where fenshu <= 80)
2
其中,两个表的关联字段为申请单号。
这是典型的一对一结构,为了避免单表字段过多而进行了拆分。可以认为是 主键共享 策略
2.1 查询身份证号为440401430103082的申请日期。
#首先从g_cardapplydetail表中找到身份证号为440401430103082的记录,
#然后通过关联字段g_applyno连接到g_cardapply表以获取申请日期。
SELECT ca.g_applydate
FROM g_cardapply ca
JOIN g_cardapplydetail cad ON ca.g_applyno = cad.g_applyno
WHERE cad.g_idcard = '440401430103082';
2.2 查询同一个身份证号码有两条以上记录的身份证号码及记录个数。
select g_idcard ,count(g_idcard)
from g_cardapplydetail
group by g_idcard
having count(g_idcard) >= 2
2.3 将身份证号码为 440401430103082 的记录在两个表中的申请状态均改为 07。
更新多表,且两表存在外键约束,有固定语法
UPDATE g_cardapply
join g_cardapplydetail
on g_cardapply.g_applyno = g_cardapplydetail.g_applyno
AND g_cardapplydetail.g_idcard = '440401430103082'
SET g_cardapply.g_state = '07',
g_cardapplydetail.g_state = '07'
2.4 删除两张表中所有姓李的记录。
DELETE ca,cad
FROM g_cardapply ca join g_cardapplydetail cad
on ca.g_applyno=cad.g_applyno
where cad.g_name like '李%';
3.
3.1 统计课程不及格[0-59】、良[60~80]、优[81-100]分别多少个。
分析:参看02节,这是属于枚举类型的逻辑判断,即按照条件进行分类。
类似的还有订单金额划分订单等级,应使用简单 CASE 函数
本题更进一步,需要在完成分类后统计每一类的数量
#FROM 后就会执行 CASE 函数,因此 CASE 中起的别名可以在GROUP BY 中用
#将表中的每一条数据都过一遍 CASE,得到一个新造列,该列名为 score_range,列的内容只能为 不及格、优、良
#GROUP BY 按照三个等级分组,就将一列 score_range 缩小为了仅三行数据
#最终,执行 SELECT,分组函数 count 在 分组的基础上执行,即统计每一组的总数.
SELECT
CASE WHEN score >= 0 AND score <= 59 THEN '不及格' WHEN score >= 60 AND score <= 80 THEN '良' WHEN score >= 81 AND score <= 100 THEN'优' ELSE '其他' END AS score_range,count(*)
FROM t_stu_score
GROUP BY score_range;
计算每科都及格的人的平均成绩。
# 和第一题非常像,因为一个人对应多科,关键是先找出所有不及格的科目,然后排除这些名字
select name, avg(score) as avgscore
from stuscore
where name not in(select name from stuscore where score < 60)
group by name;
4.
4.1 查询每个部门中“钳工”的平均工资。
# 多个部门内都有钳工,分组时应注意用两个条件分组;不管仅用部门,还是仅用工种进行分组都是不准确的
SELECT dname,job,AVG(sal) AS avg_sal
FROM t_EMPLOY
WHERE job = '钳工'
GROUP BY dname, job;
4.2 查询每个部门中“钳工”的平均工资高于2000的部门。
#在前一题的基础上进一步筛选,即分组后用 HAVING 再筛
SELECT dname
FROM t_employ
WHERE job='钳工'
GROUP BY dname,job
HAVING AVG(sal)>2000
5.
注意:字段名必须以下划线或字母开始,且只能由下划线、字母、数字组成。若字段名字中包含其他符号,对于该字段创建及后续操作时,必须以反引号包裹字段名,以让 MySQL 识别。
5.1 查询所有居住地与工作的公司在同一城市的员工的姓名。
简单的三表连接,每次 JOIN 连接一个表
SELECT e.`person-name`
FROM employee e
JOIN works w
ON e.`person-name` = w.`person-name`
JOIN company c
ON w.`company-name` = c.`company-name`
WHERE e.city=c.city;
5.2 查询比公司 B 的所有员工收入都高的所有员工的姓名。
使用子查询,先查出公司 B 的最高员工工资 ,再用所有员工工资逐条对比
SELECT `company-name`,`person-name`,salary
FROM works
# 第一个条件实际上是不需要的,因为子查询中已经查出了 SBC 公司的最高工资,如果再从整张表寻找比这个工资还高的人,这个人不可能在SBC
WHERE `company-name` <> 'Small Bank Corporation'
AND salary > (select max(salary) as maxsal from works where `company-name`='Small Bank Corporation');
5.3 找出平均工资在 10000 以上的公司及其平均工资。
# GROUP BY -- 分组函数 -- HAVING, 因此在分组函数中起别名后能被 HAVING 识别
SELECT `company-name` ,avg( salary ) avgsal
FROM works
GROUP BY `company-name`
HAVING avgsal > 10000;
6.
数据库中仅有月薪字段(month_salary),要求查询所有员工的年薪,并以年薪(year_salary)输出:
分析:
- 查询操作中,字段可以参与数学运算
- as 起别名,但实际上可以省略
#以下两句效果完全一致
select month_salary as year_salary from emp
select month_salary year_salary from emp