2012-06-01 26 views
0

我對SQL仍然比較陌生,我不完全瞭解代碼中的問題來自哪裏。下面的代碼大部分來自我的工作,所以我沒有從頭開始編寫它。該代碼基於它收集了一堆不同的信息和過濾器。如果你看看代碼,你會看到一個學生有很多與它有關的觀察學生。代碼的第一個版本返回誰與observation_id的observations_student = 2567這似乎與下面的代碼正常工作所有學生的信息:MySQL - 計數沒有返回我正在查找的值

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 

如果我改變了「AS fd_count COUNT(fdos.id)」到「fdos.id AS fdosid」我回來正確的條目數量。但是,從COUNT返回的號碼不是相同的號碼,並且不正確。任何人都可以理解這裏發生了什麼,足以解釋我做錯了什麼?

謝謝你的時間。

+0

您正在使用哪些DBMS?甲骨文? PostgreSQL的? –

+0

正在使用MySQL。 –

回答

1

我敢打賭,你正在使用MySQL。

如果你使用的任何東西:

  • GROUP BY條款;
  • HAVING子句;
  • 聚合函數,這是count()

然後將查詢被聚合之一。

這意味着,數據GROUP BY子句中指定的字段可以細分電子郵件廣告,這樣的字段應該保持原樣在選擇列表中,並在查詢的其它位置。所有其他字段應該是聚合函數的參數,否則數據庫不知道該集合中哪個值與您應該返回的組相匹配。

所有主要的數據庫會給你一個錯誤的查詢你池莉構建做的方式,因爲沒有GROUP BY子句一堆字段:s.osis_ids.ids.last_names.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; 
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 
0

速戰速決似乎是改變COUNT(fdos.id)COUNT(*)

這是一個解釋。 fdos結果爲外部已加入,因此fdos行可能不會爲連接左側的某些行返回。當它們沒有被返回時,相應的列(包括fdos.id)作爲NULL返回。但是COUNT()省略了NULL,這意味着COUNT(fdos.id)會省略連接結果集的某些行。統計的所有行的標準方式無論匹配如何,NULL等都與COUNT(*)一致。