给将军们出道挂了不少人的SQL面试题

l
lengygf
楼主 (未名空间)

有一个表记录了学生的选课情况,两个column: 学生ID和选择的课程ID,比如
001, ART1001
001, ECON1001
002, PHYS1001
...

如果此program要求学生必须修过某几门课程(不考虑挂科的情形),请写一个query筛选出没有满足此选课要求的学生ID。

要求用三种不同的方法

l
lengygf

答案:

1) self join选出符合条件的学生先

SELECT * FROM Table T1, Table T2, ...
WHERE T1.ID = T2.ID and T2.ID = T3.ID and ...
AND T1.Courseid = XXX AND T2.CourseID = XXX...

2) Intersect:
(Select StudentID from table where CourseID = xxx)
INTERSECT
(Select StudentID from table where CourseID = yyy)
INSERSECT
(Select StudentID from table where CourseID = zzz)
...

3) Common Table Expression
With CTE_CourseA AS (Select StudentID from table where CourseID = xxx);
With CTE_CourseB AS (Select StudentID from table where CourseID = yyy);
...;

SELECT DISTINCT StudentID from CourseTable WHERE StudentID in CTE_CourseA
AND
StudentID in CTE_CourseB ...

4) PIVOT Table - 先加一column的dummy data比如都是1 然后

SELECT * FROM
(
StudentCourse
) t
PIVOT(
SUM(Z)
FOR CourseID IN (AAA,BBB,CCC) AS pivot_table;

这样没选全课学生的row会出现NULL

N
Notalandlord


你是考人还是求人?
p
printf888

我问个蠢问题... “某几门课程”是给定的吗?还是可变的?
l
lengygf

当然是固定不变的啦。

【 在 printf888(foobar888) 的大作中提到: 】

: 我问个蠢问题... “某几门课程”是给定的吗?还是可变的?

l
lengygf

我自己能搞出四种方法做这题 用的着求人嘛

【 在 Notalandlord(少量土地出租) 的大作中提到: 】

: 你是考人还是求人?

E
Echowood090

回字有四种写法,我都知道
p
printf888

那应该不难吧,怎么着inner join几下就行了?我sql不好,就不献丑了...

【 在 lengygf (lengygf) 的大作中提到: 】
: 当然是固定不变的啦。
:
: 我问个蠢问题... “某几门课程”是给定的吗?还是可变的?
:

l
lengygf

这题就是看对SQL的了解程度如何 想出INNER JOIN 很不错, 不过还有好几种更高效
的方法

【 在 printf888(foobar888) 的大作中提到: 】
<br>: 那应该不难吧,怎么着inner join几下就行了?我sql不好,就不献丑了...
<br>

l
lengygf

哈哈哈让你写query 你给我整这些? 咋不说导入Python 用pandas 自带的data frame 写loop操作更简单呢?

【 在 hardpack(hardpack) 的大作中提到: 】

: 我说的这种方法,楼主肯定不知道:

: 1. 数据导入Access;

: 2. query1,列出所有ids;

: 3. query2,列出选某几门课程ids;

: 4. Find Unmatched Query Wizard,query1 vs query2。

: 大约点十下鼠标吧。

: 你研究下第四步自动生成的query,大概就知道怎么手写了。

x
xiongmaoren

我说个方法楼主有可能不知道

用r sql读这个文件,用data frame找出第二列等于某些课程的交集

python同理

l
lengygf

看我楼上回复,考你SQL让你写query 你非得整其他的东西 不挂你挂谁。

【 在 xiongmaoren(熊猫人) 的大作中提到: 】

: 我说个方法楼主有可能不知道

: 用r sql读这个文件,用data frame找出第二列等于某些课程的交集

: python同理

l
lengygf

想出一种方法不难,能想出多种解法才是这道考题的关键

你的解答等于没回答我问题

3. query2,列出选某几门课程ids;

这个就是问题的难点,如何用三种不同方法列出?

【 在 hardpack(hardpack) 的大作中提到: 】
<br>: 微软都把这玩意做成wizard了,你说这是多么常见的问题。
<br>: 核心就是query1 leftjoin query2 where id2 is null呗。
<br>: frame
<br>

p
psp

correlated sub query
Join
CTE
Temp table
l
lengygf

恩 这位大哥基本功很扎实

还有intersect和table pivoting 也可以解决

【 在 psp(I love psp) 的大作中提到: 】

: correlated sub query

: Join

: CTE

: Temp table

d
dinassor

select * from xxx where c.id not in select yyy?
lol

【 在 lengygf (lengygf) 的大作中提到: 】
: 有一个表记录了学生的选课情况,两个column: 学生ID和选择的课程ID,比如
: 001, ART1001
: 001, ECON1001
: 002, PHYS1001
: ...
: 如果此program要求学生必须修过某几门课程(不考虑挂科的情形),请写一个query筛
: 选出没有满足此选课要求的学生ID。
: 要求用三种不同的方法

l
lengygf

yyy是什么? 这才是关键

【 在 dinassor(牛磨王) 的大作中提到: 】

: select * from xxx where c.id not in select yyy?

: lol

d
dinassor

一张表里能有没选的课吗?

【 在 lengygf (lengygf) 的大作中提到: 】
: yyy是什么? 这才是关键
:
: select * from xxx where c.id not in select yyy?
:
: lol
:

l
lengygf

学生有可能没选全必修课,也有可能多选了其他无关紧要的课

【 在 dinassor(牛磨王) 的大作中提到: 】

: 一张表里能有没选的课吗?

p
psp

过奖了,好多年没用,生疏了。
【 在 lengygf (lengygf) 的大作中提到: 】
: 恩 这位大哥基本功很扎实
: 还有intersect和table pivoting 也可以解决
:
: correlated sub query
:
: Join
:
: CTE
:
: Temp table
:

d
dinassor

只要必修课都在这张表里就没啥问题啊

【 在 lengygf (lengygf) 的大作中提到: 】
: 学生有可能没选全必修课,也有可能多选了其他无关紧要的课
:
: 一张表里能有没选的课吗?
:

l
lengygf

Lol

没选全课的学生也能出现在你这个结果里

你还是回去修炼一下基本功吧

【 在 hardpack(hardpack) 的大作中提到: 】

: SELECT DISTINCT id

: FROM

: WHERE course IN (...)

: 这是难点?

l
lengygf

比如必修课A,B,C三门,表里可能没有任何一个学生满足ABC都上过这个条件,也有可能某个学生除了ABC三门课以外还上过DEF这些课

这是real life problem 解释的够清楚了

【 在 dinassor (牛磨王) 的大作中提到: 】
: 只要必修课都在这张表里就没啥问题啊

s
savering

楼上的办法都太慢。

Try this:

1. Sort by ID and course.

2. Merge multiple rows (courses) into one row (as courses_taken) by ID.

3. Select where courses_taken like "%X%Y%Z%", assuming X/Y/Z are
the 3
required courses.

l
lengygf

第二步的query如何写?

【 在 savering (无人驾驶) 的大作中提到: 】
: 楼上的办法都太慢。
: Try this:
: 1. Sort by ID and course.
: 2. Merge multiple rows (courses) into one row (as courses_taken) by ID.
: 3. Select where courses_taken like "%X%Y%Z%", assuming X/Y/Z are
: the 3
: required courses.

s
savering

现在SQL都支持。你out了。

【 在 lengygf(lengygf) 的大作中提到: 】

: 第二步的query如何写?

l
lengygf

哈哈别混水摸鱼啊 说出来是哪个命令啊

【 在 savering (无人驾驶) 的大作中提到: 】
: 现在SQL都支持。你out了。
:
: 第二步的query如何写?
:

s
savering

我就不告诉你。急死你。哈哈。

【 在 lengygf(lengygf) 的大作中提到: 】

: 哈哈别混水摸鱼啊 说出来是哪个命令啊

l
laoliu

1)
select id
from sutdent_course s
where not exists (
select 1
from student_course c
where course_id in ('ART1001', 'ECON1001')
and s.id = c.id
);

2)
select id
from student_course
where id not in (
select id
from student_course
where course_id in ('ART1001', 'ECON1001')
);

3)
select id
from student_course
minus
select id
from student_course
where course_id in ('ART1001', 'ECON1001')
;

l
lengygf

必须修过某些课意思就是要求的必修课要修全啊 哈哈

你光count有啥用,比如要求选ABC三门,某个学生选了ADE这三门课,count也能对的上啊

【 在 hardpack (hardpack) 的大作中提到: 】
: “必须修过某几门课程”,你没说修全啊?
: 好吧,
: SELECT id, COUNT(course) AS CNT
: FROM
: WHERE course IN (...)
: GROUP BY id
: HAVING cnt = sizeof(...)

l
lengygf

嘻嘻我不急,你那种笨办法说出来也得把你挂了

【 在 savering (无人驾驶) 的大作中提到: 】
: 我就不告诉你。急死你。哈哈。
:
: 哈哈别混水摸鱼啊 说出来是哪个命令啊
:

s
savering

讲真,面试现场如果问#2怎么实现,我直接喊下一个candidate。

【 在 lengygf(lengygf) 的大作中提到: 】
<br>: 嘻嘻我不急,你那种笨办法说出来也得把你挂了
<br>

l
laoliu

3) 错了,应该为:

select id
from student_course
minus
select s1.id
from student_course s1
join student_course s2 on s1.id = s2.id
where s1.course_id ='ART1001'
and s2.course_id = 'ECON1001'
;

【 在 laoliu (老六) 的大作中提到: 】
: 1)
: select id
: from sutdent_course s
: where not exists (
: select 1
: from student_course c
: where course_id in ('ART1001', 'ECON1001')
: and s.id = c.id
: );
: 2)
: ...................

l
lengygf

其余的我没试,你这2肯定不对,要求选ABC三门课,某学生只选A这门课 也能被你选中

【 在 laoliu (老六) 的大作中提到: 】
: 1)
: select id
: from sutdent_course s
: where not exists (
: select 1
: from student_course c
: where course_id in ('ART1001', 'ECON1001')
: and s.id = c.id
: );
: 2)
: ...................

l
lengygf

嘻嘻 那要看谁面试谁了

【 在 savering (无人驾驶) 的大作中提到: 】
: 讲真,面试现场如果问#2怎么实现,我直接喊下一个candidate。
:
: 嘻嘻我不急,你那种笨办法说出来也得把你挂了
:

s
savering

这道题的要点是在scalability。传统方法要一门课一门课地删选,能实现但效率是个
问题。

假如要求的科目有一百门之多呢?对table每多操作一次都是犯罪。

【 在 savering(无人驾驶) 的大作中提到: 】

: 讲真,面试现场如果问#2怎么实现,我直接喊下一个candidate。

:
l
laoliu

多年不用生疏了。subquery里用union,把选过几门课的选出来。

【 在 lengygf (lengygf) 的大作中提到: 】
: 其余的我没试,你这2肯定不对,要求选ABC三门课,某学生只选A这门课 也能被你选中

l
lengygf

应该是用Intersect 求交集而不是并集

答案在二楼

【 在 laoliu (老六) 的大作中提到: 】
: 多年不用生疏了。subquery里用union,把选过几门课的选出来。

l
laoliu

对,union和现在的没区别。忘得真快。

【 在 lengygf (lengygf) 的大作中提到: 】
: 应该是用Intersect 求交集而不是并集
: 答案在二楼

x
xlzero

老中又来秀智商

结果回头还是给烙印经理打工

天天就琢磨这点屁玩意
T
TheMatrix

我先写一个,假设选课table叫student_class,两个column叫ID和class.

with
requirement(class) as (
select 'ART1001' union all
select 'ECON1001'
--more
)
, student_req_class as (
select a.*
, case when b.class is not null then 1 else 0 end required
from student_class a
left join requirement b on a.class = b.class
)
select ID
from student_req_class
group by ID
having sum(required) < (select count(*) from requirement)
;

【 在 lengygf (lengygf) 的大作中提到: 】
: 有一个表记录了学生的选课情况,两个column: 学生ID和选择的课程ID,比如
: 001, ART1001
: 001, ECON1001
: 002, PHYS1001
: ...
: 如果此program要求学生必须修过某几门课程(不考虑挂科的情形),请写一个query筛
: 选出没有满足此选课要求的学生ID。
: 要求用三种不同的方法

r
ridgeren

茴字的N种写法

【 在 xlzero 的大作中提到: 】
:
:老中又来秀智商
:
:结果回头还是给烙印经理打工
:
:天天就琢磨这点屁玩意
:

P
Pegasi

inner join再按学生id group count distinct,然后select出count小于要求选的课程数目的就行

【 在 lengygf (lengygf) 的大作中提到: 】
: 有一个表记录了学生的选课情况,两个column: 学生ID和选择的课程ID,比如
: 001, ART1001
: 001, ECON1001
: 002, PHYS1001
: ...
: 如果此program要求学生必须修过某几门课程(不考虑挂科的情形),请写一个query筛
: 选出没有满足此选课要求的学生ID。
: 要求用三种不同的方法