MySQL - Count没有返回我正在寻找的值

时间:2012-06-01 06:50:03

标签: mysql sql count left-join

我仍然是SQL的新手,我还没有完全理解我的代码中的问题来自哪里。下面的代码主要来自我的工作,所以我没有从头开始编写代码。该代码基于它收集了大量不同的信息和过滤器。如果您查看代码,您将看到学生有许多与其相关的观察学生。代码的第一个版本返回所有拥有observation_student且observe_id = 2567的学生的信息。这似乎与以下代码一起正常工作:

SELECT DISTINCT
SUBSTRING(s.osis_id,INSTR(s.osis_id,'-')+1) AS osid,
s.id AS student_id,
CONCAT(s.last_name, ' ',s.first_name) AS sname
FROM students s

# course info
INNER JOIN 
(
    SELECT c.id AS cid,
    c.description AS cname,
    cs.date_end,
    cs.student_id,
    gl.description AS grade,
    c.gradelevel_id
    FROM courses_students cs
    INNER JOIN courses c ON c.id = cs.course_id
    INNER JOIN gradelevels gl ON gl.id = c.gradelevel_id
    WHERE
    IFNULL(cs.date_end, NOW()) >= NOW()
    AND IFNULL(c.date_end, NOW()) >= NOW()
    AND c.school_id = 1509
    AND c.subject_id = 24
) AS cs ON cs.student_id = s.id

# RTI flag info
INNER JOIN 
(
    SELECT os.id,
    os.student_id
    FROM observations o
    INNER JOIN observations_students os ON os.observation_id = 2567
    WHERE
    o.school_id = 1509
) AS os ON os.student_id = s.id

LEFT JOIN schools_students ss ON ss.student_id = s.id
WHERE s.active = 1
AND ss.school_id = 1509
AND IFNULL(ss.date_end,NOW()) >= NOW()
AND cs.gradelevel_id BETWEEN 10 AND 16

在此之后我想做的是对于每个有2567观察的学生,我想找到学生所拥有的2009年观察数。为此,我将添加另一个LEFT JOIN,完成的代码如下所示:

SELECT DISTINCT
SUBSTRING(s.osis_id,INSTR(s.osis_id,'-')+1) AS osid,
s.id AS student_id,
CONCAT(s.last_name, ' ',s.first_name) AS sname,
COUNT(fdos.id) AS fd_count
FROM students s

# course info
INNER JOIN 
(
    SELECT c.id AS cid,
    c.description AS cname,
    cs.date_end,
    cs.student_id,
    gl.description AS grade,
    c.gradelevel_id
    FROM courses_students cs
    INNER JOIN courses c ON c.id = cs.course_id
    INNER JOIN gradelevels gl ON gl.id = c.gradelevel_id
    WHERE
    IFNULL(cs.date_end, NOW()) >= NOW()
    AND IFNULL(c.date_end, NOW()) >= NOW()
    AND c.school_id = 1509
    AND c.subject_id = 24
) AS cs ON cs.student_id = s.id

# RTI flag info
INNER JOIN 
(
    SELECT os.id,
    os.student_id
    FROM observations o
    INNER JOIN observations_students os ON os.observation_id = 2567
    WHERE
    o.school_id = 1509
) AS os ON os.student_id = s.id

LEFT JOIN
(
    SELECT fdos.id,
    fdos.student_id
    FROM observations o
    INNER JOIN observations_students fdos ON fdos.observation_id = 2009
    WHERE
    o.school_id = 1509
) AS fdos ON fdos.student_id = s.id

LEFT JOIN schools_students ss ON ss.student_id = s.id
WHERE s.active = 1
AND ss.school_id = 1509
AND IFNULL(ss.date_end,NOW()) >= NOW()
AND cs.gradelevel_id BETWEEN 10 AND 16

如果我将“COUNT(fdos.id)AS fd_count”更改为“fdos.id AS fdosid”,则返回正确的条目数。但是,从COUNT返回的数字不是相同的数字,并且不正确。谁能理解这里发生了什么,足以解释我做错了什么?

感谢您的时间。

3 个答案:

答案 0 :(得分:1)

似乎os的INNER JOIN已经过滤了你的结果,只显示observe_id = 2567.因此你不能获得不同的observation_id的任何其他记录。您可以将INNER JOIN更改为LEFT JOIN,看看它是如何进行的。

SELECT DISTINCT
SUBSTRING(s.osis_id,INSTR(s.osis_id,'-')+1) AS osid,
s.id AS student_id,
CONCAT(s.last_name, ' ',s.first_name) AS sname,
COUNT(fdos.id) AS fd_count
FROM students s

# course info
INNER JOIN 
(
    SELECT c.id AS cid,
    c.description AS cname,
    cs.date_end,
    cs.student_id,
    gl.description AS grade,
    c.gradelevel_id
    FROM courses_students cs
    INNER JOIN courses c ON c.id = cs.course_id
    INNER JOIN gradelevels gl ON gl.id = c.gradelevel_id
    WHERE
    IFNULL(cs.date_end, NOW()) >= NOW()
    AND IFNULL(c.date_end, NOW()) >= NOW()
    AND c.school_id = 1509
    AND c.subject_id = 24
) AS cs ON cs.student_id = s.id

# RTI flag info
LEFT JOIN  #change this to LEFT JOIN
(
    SELECT os.id,
    os.student_id
    FROM observations o
    INNER JOIN observations_students os ON os.observation_id = 2567
    WHERE
    o.school_id = 1509
) AS os ON os.student_id = s.id

LEFT JOIN
(
    SELECT fdos.id,
    fdos.student_id
    FROM observations o
    INNER JOIN observations_students fdos ON fdos.observation_id = 2009
    WHERE
    o.school_id = 1509
) AS fdos ON fdos.student_id = s.id

LEFT JOIN schools_students ss ON ss.student_id = s.id
WHERE s.active = 1
AND ss.school_id = 1509
AND IFNULL(ss.date_end,NOW()) >= NOW()
AND cs.gradelevel_id BETWEEN 10 AND 16

答案 1 :(得分:1)

我敢打赌你在使用MySQL。

如果您使用以下任何内容:

  • GROUP BY条款;
  • HAVING条款;
  • 聚合函数,count()

然后您的查询将被聚合一个。

这意味着,数据按照GROUP BY子句中指定的字段进行分组,这些字段应按原样保留在选择列表和查询中的其他位置。所有其他字段应该是聚合函数的参数,否则数据库不知道该集合中应该返回的哪个值匹配。

所有主要数据库都会为您的查询构成错误,因为对于一堆字段没有GROUP BY子句:s.osis_ids.id,{{1 }和s.last_name。 MySQL不会。相反,它会隐式地对数据进行分组。我不知道什么是分组标准,我不想,因为这种行为容易出错且不可靠。

相反,您的查询应该被重写。 最简单的方法是:

  • 使用不具有s.first_name功能的现有查询,即获取count()的列表;
  • 将整个查询用作另一个子查询,省略fdos.id子句;
  • 数学生。

这样的事情:

DISTINCT

答案 2 :(得分:0)

快速解决方法似乎是将COUNT(fdos.id)更改为COUNT(*)

这是一个解释。 fdos结果是外部 -joined,因此对于连接左侧的某些行,可能不会返回fdos行。如果未返回它们,则相应的列(包括fdos.id)将返回NULL。但是COUNT()省略了NULL,这意味着COUNT(fdos.id)将省略连接结果集的某些行。无论匹配,NULL等计算所有行的标准方法都是COUNT(*)