我有一些不同的SQL表,我需要执行一些计数。这是我的工作,显然数据是保密的,但我会尝试将其抽象为类似的东西。想象一下大学注册办公室......
我们的第一个表格列出了学生已完成的所有课程。
表:student_courses
student_id | course_id
----------------------
123456 | MATH101
123456 | MATH203
785426 | PHYS305
... | ...
我们还为我们大学的不同部门提供表格,列出(除其他外)课程ID和课程年级:
表:math_courses
course_id | year
--------------------
MATH101 | 1
MATH201 | 2
MATH202 | 2
CALC103 | 1
STAT402 | 4
... | ...
想象一下类似的science_courses
和general_courses
表。该大学还有其他部门,但我们现在只考虑这三个部门。
我们正在寻找的是每年有多少学生达到年/部门的组合。
例如,如果学生同时选修了MATH101和MATH201,那么数学系的“年”将被视为“2”。
并非所有学生都完成了所有系的课程,并非所有学生都必须参加这三个系的任何课程。
基本上,我想制作下表:
max_math_year | max_science_year | max_general_year | student_count
---------------------------------------------------------------------
NULL | NULL | NULL | 39847
NULL | NULL | 1 | 172
NULL | NULL | 2 | 0
... | ... | ... | ...
4 | 4 | 4 | 4986
我已经建立了一个临时表来存储每个学生的最高级别,它似乎正常工作,所以为了这个练习,假设我们有下表:
表:#student_maximums
student_id | max_math_year | max_science_year | max_general_year
----------------------------------------------------------------
123465 | 2 | NULL | 1
782514 | 3 | 1 | NULL
874252 | NULL | NULL | NULL
... | ... | ... | ...
我希望当一行没有符合某个组合的学生时返回0
,但如果我对上表进行计数,则不会返回零值。
大多数时候我会用LEFT OUTER JOIN
来包含零,但在这种情况下,我们会计算最初来自四个不同表的数据。我考虑使用CROSS JOIN
,但行中不包含NULL
值,这也是我需要的。
谢谢!
答案 0 :(得分:4)
我不确定我是否理解正确,但这是你想要的吗?
select
coalesce(max_math_year, 0)
,coalesce(max_science_year, 0)
,coalesce(max_general_year, 0)
,count(*)
from #student_maximums
group by
coalesce(max_math_year, 0)
,coalesce(max_science_year, 0)
,coalesce(max_general_year, 0)
答案 1 :(得分:1)
我认为这就是你所需要的(虽然我不是绝对肯定的 - 如果它不能解释什么是错的):
UPDATE #student_maximums SET max_math_year = 0 WHERE max_math_year is NULL
UPDATE #student_maximums SET max_science_year = 0 WHERE max_science_year is NULL
UPDATE #student_maximums SET max_general_year = 0 WHERE max_general_year is NULL
SELECT max_math_year, max_science_year, max_general_year, count(*) as student_count
FROM #student_maximums
GROUP BY max_math_year, max_science_year, max_general_year
ORDER BY 1, 2, 3
答案 2 :(得分:0)
基于这两个建议,我想出了以下内容。我对合并的值执行了连接,因此空行实际上会在表中排成一行。
注意,我能够在课程表中插入行。如果我不是,我会在查询中联合零值行。
INSERT INTO math_courses (0, NULL)
INSERT INTO science_courses (0, NULL)
INSERT INTO general_courses (0, NULL)
SELECT
COALESCE(m.max_math_year, 0)
, COALESCE(s.max_science_year, 0)
, COALESCE(g.max_general_year, 0)
, COUNT(DISTINCT student_id)
FROM
math_courses m
CROSS JOIN
science_courses s
CROSS JOIN
general_courses g
LEFT OUTER JOIN
student_maximums sm
ON COALESCE(sm.max_math_year, 0) = COALESCE(m.year, 0)
AND COALESCE(sm.max_science_year, 0) = COALESCE(s.year, 0)
AND COALESCE(sm.max_general_year, 0) = COALESCE(g.year, 0)
GROUP BY
COALESCE(m.max_math_year, 0)
, COALESCE(s.max_science_year, 0)
, COALESCE(g.max_general_year, 0)
ORDER BY
COALESCE(m.max_math_year, 0)
, COALESCE(s.max_science_year, 0)
, COALESCE(g.max_general_year, 0)