我仍然是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返回的数字不是相同的数字,并且不正确。谁能理解这里发生了什么,足以解释我做错了什么?
感谢您的时间。
答案 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_id
,s.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(*)
。