@[目录]
这是超经典SQL练习题,做完这些你的SQL就过关了的题目在PostgreSQL14上的解答。
CREATE DATABASE edudb_test;
CREATE TABLE student(s_id VARCHAR(10),s_name VARCHAR(20),s_age DATE,s_sex CHAR(1)
);
INSERT INTO student(s_id, s_name, s_age, s_sex) VALUES('01' , '赵雷' , '19900101' , '男'),('02' , '钱电' , '19901221' , '男'),('03' , '孙风' , '19900520' , '男'),('04' , '李云' , '19900806' , '男'),('05' , '周梅' , '19911201' , '女'),('06' , '吴兰' , '19920301' , '女'),('07' , '郑竹' , '19890701' , '女'),('08' , '王菊' , '19900120' , '女')
;
CREATE TABLE course(c_id VARCHAR(10),c_name VARCHAR(20),t_id VARCHAR(10)
);
INSERT INTO course VALUES('01' , '语文' , '02'),('02' , '数学' , '01'),('03' , '英语' , '03')
;
CREATE TABLE teacher(t_id VARCHAR(10),t_name VARCHAR(20)
);
INSERT INTO teacher VALUES('01' , '张三'),('02' , '李四'),('03' , '王五')
;
CREATE TABLE score(s_id VARCHAR(10),c_id VARCHAR(10),sc_score DECIMAL(3,1)
);
INSERT INTO score VALUES('01' , '01' , 80),('01' , '02' , 90),('01' , '03' , 99),('02' , '01' , 70),('02' , '02' , 60),('02' , '03' , 80),('03' , '01' , 80),('03' , '02' , 80),('03' , '03' , 80),('04' , '01' , 50),('04' , '02' , 30),('04' , '03' , 20),('05' , '01' , 76),('05' , '02' , 87),('06' , '01' , 31),('06' , '03' , 34),('07' , '02' , 89),('07' , '03' , 98)
;
SELECT st.*, sc1.sc_score FROM student AS st INNER JOIN score AS sc1 ON st.s_id = sc1.s_idWHERE c_id = '02' AND sc1.sc_score > (SELECT sc2.sc_score FROM score AS sc2 WHERE c_id='01' AND sc1.s_id = sc2.s_id);
/*原博主的方法*/
SELECT sc1.*, sc2.c_id, sc2.sc_score
FROM (SELECT * FROM score WHERE c_id='01') AS sc1
LEFT JOIN
(SELECT * FROM score WHERE c_id='02') AS sc2
ON sc1.s_id = sc2.s_id
WHERE sc1.sc_score > sc2.sc_score;
SELECT sc1.*, sc2.c_id, sc2.sc_score
FROM (SELECT * FROM score WHERE c_id='01') AS sc1
INNER JOIN
(SELECT * FROM score WHERE c_id='02') AS sc2
ON sc1.s_id = sc2.s_id;
SELECT sc1.*, sc2.c_id, sc2.sc_score
FROM (SELECT * FROM score WHERE c_id='01') AS sc1
LEFT JOIN
(SELECT * FROM score WHERE c_id='02') AS sc2
ON sc1.s_id = sc2.s_id;
SELECT sc2.*
FROM (SELECT * FROM score WHERE c_id='01') AS sc1
RIGHT JOIN
(SELECT * FROM score WHERE c_id='02') AS sc2
ON sc1.s_id = sc2.s_id
WHERE sc1.sc_score is null;
/*原博主的方法*/
SELECT sc2.*
FROM score AS sc2
WHERE sc2.c_id = '02' and sc2.s_id not in (SELECT s_id FROM score WHERE c_id = '01');
SELECT st.s_id, st.s_name, sc.avg_score FROM student AS st INNER JOIN (SELECT s_id, AVG(sc_score) AS avg_score FROM score GROUP BY s_id) AS sc ON st.s_id = sc.s_idWHERE sc.avg_score >= 60;
SELECT st.*FROM student AS st INNER JOIN (SELECT DISTINCT s_id FROM score) AS sc ON st.s_id = sc.s_id;
/*原博主的方法
因为没有连接查询,原博主的效率更高。*/
SELECT * FROM student WHERE s_id in (SELECT DISTINCT s_id FROM score);
SELECT st.s_id, st.s_name, sc.course_count, sc.sum_scoreFROM student AS st LEFT JOIN (SELECT s_id, count(c_id) AS course_count, sum(sc_score) as sum_score FROM score GROUP BY s_id) AS sc ON st.s_id = sc.s_id;
SELECT st.*FROM student AS st INNER JOIN (SELECT DISTINCT s_id FROM score) AS sc ON st.s_id = sc.s_id;
SELECT count(t_id) FROM teacher WHERE t_name like '李%';
SELECT st.* FROM student AS st LEFT JOIN score AS sc ON st.s_id = sc.s_id WHERE sc.c_id = (SELECT c_id FROM course WHERE t_id = (SELECT t_id FROM teacher WHERE t_name = '张三'))
;
/*原博主的方法*/
SELECT * FROM student WHERE s_id in (SELECT DISTINCT s_id FROM scoreWHERE c_id = (SELECT c_id FROM Course WHERE t_id = (SELECT t_id FROM teacherWHERE t_name = '张三'))
);
/*这里添加了IS NULL的条件。如果删除此条件,则不会显示一门课没考的同学信息*/
SELECT st.*, course_count FROM student AS st LEFT JOIN (SELECT s_id, count(c_id) AS course_count FROM score GROUP BY s_id) AS sc ON st.s_id &#61; sc.s_id WHERE sc.course_count<3 OR sc.course_count IS NULL
;
/*原博主的方法*/
SELECT * FROM student WHERE s_id IN (SELECT s_id FROM scoreGROUP BY s_id HAVING count(c_id)<3
);
SELECT * FROM student WHERE s_id NOT IN (SELECT s_id FROM scoreGROUP BY s_id HAVING count(c_id)&#61;3
);
SELECT st.* FROM student AS st INNER JOIN (SELECT DISTINCT s_id FROM score WHERE c_id IN (SELECT c_id FROM score WHERE s_id&#61;&#39;01&#39;) AND s_id!&#61;&#39;01&#39;) AS sc ON st.s_id &#61; sc.s_id
;
/*原博主的方法*/
SELECT * FROM student WHERE s_id IN (SELECT s_id FROM scoreWHERE c_id in (SELECT DISTINCT c_id FROM score WHERE s_id&#61;&#39;01&#39;)AND s_id!&#61;&#39;01&#39;
);
SELECT st.* FROM student AS st INNER JOIN (SELECT s_id, count(c_id) AS count_c_id FROM score GROUP BY s_id) AS scON st.s_id &#61; sc.s_idWHERE sc.count_c_id &#61; (SELECT count(c_id) FROM score WHERE s_id&#61;&#39;01&#39;)
;
/*原博主的方法*/
SELECT * FROM studentWHERE s_id IN (SELECT s_id FROM score GROUP BY s_id HAVING count(c_id)&#61;(SELECT count(c_id) FROM score WHERE s_id&#61;&#39;01&#39;));
SELECT st.* FROM student AS stWHERE st.s_id NOT IN (SELECT s_id FROM score WHERE c_id IN (SELECT c_id FROM course WHERE t_id &#61; (SELECT t_id FROM teacher WHERE t_name &#61; &#39;张三&#39;)));
;
SELECT st.s_id, st.s_name, sc.avg_sc FROM student AS st INNER JOIN (SELECT DISTINCT s_id, count(sc_score) AS count_sc, avg(sc_score) AS avg_sc FROM score GROUP BY s_id) AS sc ON st.s_id &#61; sc.s_id WHERE sc.count_sc >&#61;2 AND sc.avg_sc <60
;
SELECT st.s_id, st.s_name, sc.sc_score
FROM student AS st
RIGHT JOIN score AS sc
ON st.s_id&#61;sc.s_id
WHERE sc.c_id&#61;&#39;01&#39; AND sc.sc_score <60
ORDER BY sc.sc_score DESC;
SELECT st.* FROM student AS st LEFT JOIN (SELECT s_id, sc_score FROM score WHERE c_id&#61;&#39;01&#39;) AS sc ON st.s_id &#61; sc.s_id WHERE sc.sc_score<60 ORDER BY sc.sc_score DESC
;
以如下形式显示&#xff1a;课程 ID&#xff0c;课程 name&#xff0c;最高分&#xff0c;最低分&#xff0c;平均分&#xff0c;及格率&#xff0c;中等率&#xff0c;优良率&#xff0c;优秀率
及格为>&#61;60&#xff0c;中等为&#xff1a;70-80&#xff0c;优良为&#xff1a;80-90&#xff0c;优秀为&#xff1a;>&#61;90
要求输出课程号和选修人数&#xff0c;查询结果按人数降序排列&#xff0c;若人数相同&#xff0c;按课程号升序排列
WITH RECURSIVE sc1(c_id, score, jige, zhongdeng, youliang,youxiu) AS (
SELECT c_id, sc_score, CASE WHEN sc_score>&#61;60 THEN 1 ELSE 0 END AS jige, CASE WHEN sc_score>&#61;70 THEN 1 ELSE 0 END AS zhongdeng,CASE WHEN sc_score>&#61;80 THEN 1 ELSE 0 END AS youliang,CASE WHEN sc_score>&#61;90 THEN 1 ELSE 0 END AS youxiuFROM score
)
SELECT c_id, count(score), max(score) AS max_sc, min(score) AS min_sc, round(avg(score),2) AS avg_sc, round(avg(jige)*100,2) AS per_jige,round(avg(zhongdeng)*100,2) AS per_zhongdeng,round(avg(youliang)*100,2) AS per_youliang,round(avg(youxiu)*100,2) AS per_youxiugFROM sc1 GROUP BY c_idORDER BY count(score) DESC, c_id
;
SELECT st.s_id, st.s_name, RANK() OVER(ORDER BY sc_score DESC) AS rank1, sc.sc_score
FROM (SELECT s_id, sc_score FROM score WHERE c_id&#61;&#39;01&#39;) AS sc INNER JOIN student AS st
ON sc.s_id&#61;st.s_id
;
SELECT st.s_id, st.s_name, DENSE_RANK() OVER(ORDER BY sc_score DESC) AS rank1, sc.sc_score
FROM (SELECT s_id, sc_score FROM score WHERE c_id&#61;&#39;01&#39;) AS sc INNER JOIN student AS st
ON sc.s_id&#61;st.s_id
;
SELECT st.s_id, st.s_name, RANK() OVER(ORDER BY sum_score DESC) AS rank1, sc.sum_score
FROM (SELECT s_id, sum(sc_score) AS sum_scoreFROM score GROUP BY s_id) AS sc INNER JOIN student AS st
ON sc.s_id&#61;st.s_id;
SELECT st.s_id, st.s_name, DENSE_RANK() OVER(ORDER BY sum_score DESC) AS rank1, sc.sum_score
FROM (SELECT s_id, sum(sc_score) AS sum_scoreFROM score GROUP BY s_id) AS sc INNER JOIN student AS st
ON sc.s_id&#61;st.s_id;
注&#xff1a;题干中分数段[100-85]用的是闭区间&#xff0c;会导致85、70和60被重复计算。
所以改为半开区间&#xff08;100-85]&#xff0c;&#xff08;85-70]&#xff0c;&#xff08;70-60]&#xff0c;&#xff08;60-0]。
WITH RECURSIVE sc1(c_id, score) AS (
SELECT c_id, sc_score, CASE WHEN sc_score<60 THEN 1 ELSE 0 END AS scale1, CASE WHEN sc_score>&#61;60 AND sc_score<70 THEN 1 ELSE 0 END AS scale2,CASE WHEN sc_score>&#61;70 AND sc_score<85 THEN 1 ELSE 0 END AS scale3,CASE WHEN sc_score>&#61;85 THEN 1 ELSE 0 END AS scale4FROM score
)
SELECT sc1.c_id, course.c_name,sum(sc1.scale1) AS scale1, sum(sc1.scale2) AS scale2, sum(sc1.scale3) AS scale3, sum(sc1.scale4) AS scale4, round(avg(scale1)*100,2) AS per_scale1,round(avg(scale2)*100,2) AS per_scale2,round(avg(scale3)*100,2) AS per_scale3,round(avg(scale4)*100,2) AS per_scale4FROM sc1 INNER JOIN course ON sc1.c_id&#61;course.c_idGROUP BY sc1.c_id, course.c_name
;
SELECT * FROM (SELECT *, RANK() OVER(PARTITION BY c_id order by sc_score DESC) AS rank1FROM score) AS sc
WHERE rank1<&#61;3
;
SELECT cr.c_name, count(sc.s_id)
FROM score AS sc RIGHT JOIN course AS cr
ON sc.c_id &#61; cr.c_id
GROUP BY cr.c_name;
SELECT st.s_id, st.s_name
FROM student AS st
INNER JOIN (SELECT s_id, count(c_id) AS count_c_idFROM scoreGROUP BY s_id) AS sc
ON st.s_id &#61; sc.s_id
WHERE sc.count_c_id &#61; 2
;
/*原博主的方法*/
SELECT s_id, s_name FROM student
WHERE s_id IN (SELECT s_id FROM (SELECT s_id, count(c_id) AS count_c_id FROM score GROUP BY s_id) AS scWHERE count_c_id &#61; 2
);
SELECT s_sex, count(s_id) FROM student GROUP BY s_sex;
/*使用了正则表达式*/
SELECT student.* FROM student WHERE s_name~&#39;.*风.*&#39;;SELECT student.* FROM student WHERE s_name LIKE &#39;%风%&#39;;
WITH RECURSIVE st1 AS (SELECT s_name, count(s_name) AS count_name FROM student GROUP BY s_name, s_sex
)
SELECT student.s_name FROM student LEFT JOIN st1 ON student.s_name &#61; st1.s_name WHERE st1.count_name>1;
SELECT * FROM student WHERE EXTRACT(YEAR FROM s_age)&#61;1990;
SELECT c_id, avg(sc_score) AS avgsc
FROM score
GROUP BY c_id
ORDER BY avgsc DESC, c_id
;
SELECT st.s_id, st.s_name, sc.avg_score
FROM student AS st INNER JOIN (SELECT s_id, avg(sc_score) AS avg_score FROM score GROUP BY s_id) AS sc
ON st.s_id &#61; sc.s_id
WHERE sc.avg_score>&#61;85;
SELECT s_id, sc_score
FROM score LEFT JOIN course
ON score.c_id &#61; course.c_id
WHERE course.c_name&#61;&#39;数学&#39; AND score.sc_score<60;
SELECT st.s_name, sc2.c_name, sc2.sc_score FROM (SELECT sc.s_id, course.c_name, sc.sc_score FROM score AS sc LEFT JOIN course ON sc.c_id &#61; course.c_id)
AS sc2 RIGHT JOIN student AS st
ON sc2.s_id &#61; st.s_id;
SELECT st.s_name, sc2.c_name, sc2.sc_score FROM (SELECT sc.s_id, course.c_name, sc.sc_score FROM score AS sc LEFT JOIN course ON sc.c_id &#61; course.c_id)
AS sc2 RIGHT JOIN student AS st
ON sc2.s_id &#61; st.s_id
WHERE sc2.sc_score>&#61;70;
SELECT st.s_name, sc2.c_name, sc2.sc_score FROM (SELECT sc.s_id, course.c_name, sc.sc_score FROM score AS sc LEFT JOIN course ON sc.c_id &#61; course.c_id)
AS sc2 RIGHT JOIN student AS st
ON sc2.s_id &#61; st.s_id
WHERE sc2.sc_score<60;
SELECT st.s_id, st.s_name
FROM student AS st RIGHT JOIN score AS sc
ON st.s_id&#61;sc.s_id
WHERE sc.c_id &#61; &#39;01&#39; AND sc.sc_score>&#61;80;
SELECT c_id, count(s_id) FROM score GROUP BY c_id;
SELECT st.*, sc.sc_score
FROM student AS st RIGHT JOIN score AS sc
ON st.s_id &#61; sc.s_id
WHERE sc.c_id &#61; (SELECT c_id FROM course INNER JOIN teacher ON course.t_id &#61; teacher.t_id WHERE teacher.t_name &#61; &#39;张三&#39;)
ORDER BY sc_score DESC
LIMIT 1;
成绩有重复&#xff0c;意味着成绩最高的可能是多个
SELECT st.*, sc.sc_score
FROM student AS st RIGHT JOIN score AS sc
ON st.s_id &#61; sc.s_id
WHERE sc.sc_score &#61; (SELECT max(sc2.sc_score) FROM score AS sc2 WHERE c_id &#61; (SELECT c_id FROM course INNER JOIN teacher ON course.t_id &#61; teacher.t_id WHERE teacher.t_name &#61; &#39;张三&#39;))
;
WITH RECURSIVE sc2 AS (SELECT c_id, count(s_id) as count_s_id, sc_score FROM score GROUP BY c_id, sc_score)
SELECT sc.s_id, sc.c_id, sc.sc_score
FROM score AS sc INNER JOIN sc2
ON sc.sc_score &#61; sc2.sc_score AND sc.c_id &#61; sc2.c_id
WHERE sc2.count_s_id >1;
SELECT st.s_id, st.s_name, sc.c_id, sc.rank1
FROM student AS st
RIGHT JOIN (SELECT s_id, c_id, ROW_NUMBER() over(PARTITION BY c_id order by sc_score DESC) AS rank1 FROM score) AS sc
ON st.s_id &#61; sc.s_id
WHERE sc.rank1<3
ORDER BY sc.c_id, sc.rank1
;
SELECT c_id, count_s_id
FROM (SELECT c_id, count(s_id) AS count_s_id FROM score GROUP BY c_id) AS sc
WHERE count_s_id>5;
SELECT s_id
FROM (SELECT s_id, count(c_id) AS count_c_id FROM score GROUP BY s_id) AS sc
WHERE count_c_id>1;
SELECT s_id
FROM (SELECT s_id, count(c_id) AS count_c_id FROM score GROUP BY s_id) AS sc
WHERE count_c_id&#61;3;
SELECT s_id, EXTRACT(YEAR FROM NOW())-EXTRACT(YEAR FROM s_age) AS age
FROM student;
SELECT s_id, date_part(&#39;year&#39;,age(s_age)) AS age
FROM student;
SELECT s_id,s_name,s_age FROM (SELECT s_id,s_name,s_age, EXTRACT(week FROM s_age) AS num_week FROM student) AS st
WHERE num_week &#61; EXTRACT(week FROM now());
SELECT s_id,s_name,s_age FROM (SELECT s_id,s_name,s_age, EXTRACT(week FROM (s_age - interval &#39;1 week&#39;)) AS num_week FROM student) AS st
WHERE num_week &#61; EXTRACT(week FROM now());
SELECT s_id,s_name,s_age FROM (SELECT s_id,s_name,s_age, date_part(&#39;month&#39;, s_age) AS birth_monthFROM student) AS st
WHERE birth_month &#61; EXTRACT(month FROM now());
SELECT s_id,s_name,s_age FROM (SELECT s_id,s_name,s_age, EXTRACT(month FROM (s_age - interval &#39;1 month&#39;)) AS num_month FROM student) AS st
WHERE num_month &#61; EXTRACT(month FROM now());&#96;