0

私はまだSQLにかなり慣れていないので、コードの問題がどこから来ているのか完全には理解していません. 以下のコードはほとんど私の仕事から来ているので、最初から書いたわけではありません。コードはさまざまな情報を収集し、それに基づいてフィルター処理します。コードを見ると、学生には関連する多くのobservations_studentsがあることがわかります。コードの最初のバージョンは、observation_id = 2567 のobservations_student を持つすべての生徒の情報を返します。これは、次のコードで正しく動作するようです。

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

MySQL を使用していることは間違いありません。

次のいずれかを使用する場合:

  • GROUP BY句;
  • HAVING句;
  • 集約関数、count()つまり

次に、クエリが集約されます。

これは、データ句で指定されたフィールドによってグループ化されることを意味しGROUP BYます。そのようなフィールドは、選択リストやクエリの他の場所にそのまま保持する必要があります。他のすべてのフィールドは集計関数の引数である必要があります。そうしないと、データベースは、グループに一致するセットからどの値を返す必要があるかわかりません。

GROUP BYすべての主要なデータベースでは、一連のフィールドに対する句がないため、このように構築されたクエリに対してエラーが発生します: s.osis_ids.ids.last_nameおよびs.first_name. MySQL はそうしません。代わりに、暗黙的にデータをグループ化します。グループ化の基準が何であるかはわかりません。この動作はエラーが発生しやすく、信頼性が低いため、グループ化したくありません。

代わりに、クエリを書き直す必要があります。最も簡単な方法は次のとおりです。

  • 関数なしで既存のクエリを使用します。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 に答える