0

我对 SQL 还是很陌生,我还没有完全理解我的代码中的问题来自哪里。下面的代码主要来自我的工作,所以我不是从头开始编写的。该代码收集了一堆不同的信息并基于它进行过滤。如果您查看代码,您会看到一个学生有许多与之相关的observations_students。代码的第一个版本返回所有具有observation_student 的学生的信息,observation_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 返回的数字不是同一个数字,也不正确。谁能理解这里发生的事情足以解释我做错了什么?

感谢您的时间。

4

3 回答 3

1

似乎 os 的 INNER JOIN 已经过滤了你的结果,只显示observation_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
于 2012-06-01T07:06:17.273 回答
1

我敢打赌你正在使用 MySQL。

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

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

那么您的查询将被聚合一个。

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

对于按照您的方式构建的查询,所有主要数据库都会给您一个错误,因为GROUP BY一堆字段没有子句: s.osis_ids.id和. MySQL 不会。相反,它将隐式分组数据。我不知道分组标准是什么,我也不想这样做,因为这种行为容易出错且不可靠。s.last_names.first_name

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

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

像这样的东西:

SELECT osid, student_id, sname, count(fdos_id) AS fd_count
  FROM (
    SELECT
        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,
        fdos.id AS fdos_id
      FROM students s
       ...
  ) AS src
 GROUP BY osid, student_id, sname
 ORDER BY osid, student_id, sname;
于 2012-06-01T07:09:19.580 回答
0

一个快速修复似乎是更改COUNT(fdos.id)COUNT(*).

这是一个解释。结果fdos连接的,因此fdos连接左侧的某些行可能不会返回行。当它们没有被返回时,对应的列(包括fdos.id)被返回为 NULL。但是COUNT()省略了 NULL,这意味着COUNT(fdos.id)会省略连接结果集中的某些行。无论匹配、NULL 等如何计算所有行的标准方法是使用COUNT(*).

于 2012-06-01T08:11:40.530 回答