对count和rows重用mysql查询的主体

时间:2016-11-07 13:32:08

标签: mysql

因为我正在使用框架(Magento),所以我无法直接控制实际执行的SQL。我可以构建查询的各个部分,但在不同的上下文中,它在进入数据库之前以不同的方式进行修改。

以下是我正在使用的简化示例。

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. 在选择
  3. 中添加count(*)
  4. 删除任何group by子句
  5. 在这次屠杀之后,我的上述查询变为

    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 个答案:

答案 0 :(得分:1)

原始查询的问题是GROUP BY子句。通过保留GROUP BY子句来选择COUNT(*)将导致两行包含每个用户的多个类:

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

删除GROUP BY子句只会从LEFT JOIN中重新调整所有行的数量:

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

我看到的唯一方法是,magento可以解决这个问题,就是将原始查询放入子查询(派生表)并计算结果的行数。但这可能会导致糟糕的表现。我也可以使用异常,抱怨带有GROUP BY子句的查询不能用于分页(或类似的东西)。只返回一个意想不到的结果可能是图书馆可以做的最差的事情。

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

在SELECT子句中为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" )

但是,我会重写查询以使用INNER JOIN而不是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

另外 - 由于MySQL优化器,它甚至会表现得更好,这通常会为使用JOIN和GROUP BY的查询创建错误的执行计划。