加入T-SQL时计算零值

时间:2013-09-16 21:17:25

标签: sql sql-server database join null

我有一些不同的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_coursesgeneral_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值,这也是我需要的。

谢谢!

3 个答案:

答案 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)