2016-11-07 61 views
1

因爲我正在使用框架(Magento),所以我沒有直接控制實際執行的SQL。我可以構建查詢的各個部分,但在不同的上下文中,它在進入數據庫之前以不同的方式進行修改。爲計數和行重複使用mysql查詢的主體

下面是我正在使用的一個簡單示例。

students  enrolments 
--------  ------------------ 
id| name  student_id| class 
--+-----  ----------+------- 
1| paul     1|biology 
2|james     1|english 
3| jo     2| maths 
         2|english 
         2| french 
         3|physics 
         3| maths 

的查詢,以顯示誰是一起學習英語的所有這些學生就讀的課程,所有學生將是:

SELECT name, GROUP_CONCAT(enrolments.class) AS classes 
FROM students LEFT JOIN enrolments ON students.id=enrolments.student_id 
WHERE students.id IN (SELECT e.student_id 
         FROM enrolments AS e 
         WHERE e.class LIKE "english") 
GROUP BY students.id 

這將產生預期的結果

name|    classes 
----+---------------------- 
paul|biology, english 
james|maths, english, french 

如果不是因爲Magento自動使用部分文件這一事實,計算學習英語的學生人數將變得微不足道我的第一個問題。對於計數,它會修改我的原始查詢,如下所示:

  1. 刪除所選的列。這將是nameclasses列。
  2. 添加一個count(*)列選擇
  3. 刪除任何group by條款

這種屠殺之後,我上面的查詢變得

SELECT COUNT(*) 
FROM students LEFT JOIN enrolments ON students.id=enrolments.student_id 
WHERE students.id IN (SELECT e.student_id 
         FROM enrolments AS e 
         WHERE e.class LIKE "english") 

這不會給我的學生的入學人數上我需要英語課程。相反,它會給我所有參加英語課程的學生的總入學人數。

我試圖想出一個查詢,可以在上下文中使用,計數和獲取行。我可以保留任何連接子句和where子句,這就是它。

回答

1

原始查詢的問題是GROUP BY子句。通過保持GROUP BY子句會導致成兩排,若干等級爲每個用戶選擇COUNT(*)

| COUNT(*) | 
|----------| 
|  2 | 
|  3 | 

卸下GROUP BY子句將只retun從左邊的所有行數JOIN:

| COUNT(*) | 
|----------| 
|  5 | 

我看到,magento可以解決這個問題的唯一方法是將原始查詢放入子查詢(派生表)並計算結果的行數。但那可能會導致糟糕的表現。我也可以很好地處理一個異常,抱怨帶有GROUP BY子句的查詢不能用於分頁(或類似的東西)。只是返回一個意想不到的結果可能是圖書館可以做的最糟糕的事情。

Well, it just so happens I have a solution. :-)

SELECT子句中使用子查詢corelated爲GROUP_CONCAT。這樣你就不需要一個GROUP BY子句。

SELECT name, (SELECT GROUP_CONCAT(enrolments.class) 
       FROM enrolments 
       WHERE enrolments.student_id = students.id 
     ) AS classes 
FROM students 
WHERE students.id IN (SELECT e.student_id 
         FROM enrolments AS e 
         WHERE e.class LIKE "english") 

不過,我想重寫查詢使用內部聯接,而不是IN條件:

SELECT s.name, (
    SELECT GROUP_CONCAT(e2.class) 
    FROM enrolments e2 
    WHERE e2.student_id = s.id 
) AS classes 
FROM students s 
JOIN enrolments e1 
    ON e1.student_id = s.id 
WHERE e1.class = "english"; 

兩個查詢將返回相同的結果作爲您的原始之一。

| name | classes    | 
|-------|----------------------| 
| paul | biology,english  | 
| james | maths,english,french | 

但修改我的magento時也返回正確的計數。

| COUNT(*) | 
|----------| 
|  2 | 

演示:http://rextester.com/OJRU38109

另外 - 有很好的機會,它甚至會表現得更好,由於MySQLs優化,這往往與聯接和GROUP BY的查詢生成錯誤的執行計劃。

+0

不幸的是,正如我所提到的,Magento在構建計數查詢之前去掉列。這意味着它會放棄你的相關子查詢。感謝您的嘗試。 – Dom

+0

您的查詢可以通過將子查詢從選定列轉移到聯接來使用Magento的結構。但是,由於子查詢會針對外部表的每次迭代運行,因此這非常慢。 – Dom

+0

「不幸的是,正如我所提到的,Magento在構建計數查詢之前將列刪除」 - 是的。計數將等於我查詢中的行數。所以有什麼問題? –