使用HAVING GROUP_CONCAT计算记录行

时间:2014-03-12 10:55:02

标签: mysql sql

我的问题(也许)有点复杂,我试着写下来可以理解。 我有一个PHP类,它根据几种情况和参数生成MySQL查询(然后在dinamyc表中显示查询结果)。 例如,这里有表格和示例查询:

table relations

很简单,有用户,每个用户可以分配一个或多个配置文件。 例如,我们只有一个用户,他有两个配置文件:

[USER]
userid    login     password     status    reg_date
------    -------   ----------   ------    -------------------
1         JohnDoe   hd98349...   0         2014-01-09 16:00:55

[PROFILE]
profile_id  profile_name    
----------  ------------
1           admin
2           root
3           user

[USER_PROFILE]
relation_id   user   profile
-----------   -----  -------
1             1      1
2             1      2

我的PHP代码生成一个如下所示的查询:

SELECT 
    userid AS 'User id', 
    login AS 'User name', 
    GROUP_CONCAT(profile_name SEPARATOR ', ') AS 'Profile(s)', 
    `status`  
FROM `user` LEFT JOIN user_profile ON `user`.userid = user_profile.`user`
         LEFT JOIN `profile` ON user_profile.`profile` = `profile`.profile_id  
WHERE 
    status IN (0, 1) 
ORDER BY reg_date ASC 
LIMIT 0 ,10

此查询的结果是:

[RESULT]
User id    User name    Profile(s)   status
-------    ---------    ----------   ------
1          JohnDoe      root, admin  0

当我想在源自子查询或复杂表达式的列(例如GROUP_CONCAT(profile_name SEPARATOR ', '))上使用过滤器时,我得到错误的结果:

SELECT COUNT(*) AS 'all_rows'  
FROM `user` LEFT JOIN user_profile ON `user`.userid = user_profile.`user`
      LEFT JOIN `profile` ON user_profile.`profile` = `profile`.profile_id  WHERE          status IN (0, 1) 
HAVING GROUP_CONCAT(profile_name SEPARATOR ', ') LIKE '%root%'

这将导致:' all_rows' => 2。 这是因为HAVING中的GROUP_CONCAT赢了组,但是如果我把它放在SELECT中就像:SELECT COUNT(GROUP_CONCAT(profile_name SEPARATOR','))我得到一个错误

所以问题是如何在过滤器(WHERE / HAVING)表达式中使用GROUP_CONCAT获取所有行的数量?

编辑:在运行主查询之前,我需要知道它会产生多少记录行,而不受LIMIT限制。我使用它来计算LIMIT的起始行值以进行分页。

3 个答案:

答案 0 :(得分:0)

你能试试这个结果吗?您并没有告诉查询引擎要分组的内容,而且似乎猜错了。

SELECT `user`.userid,
    GROUP_CONCAT(profile_name SEPARATOR ', ') as roles,
    COUNT(*) AS 'all_rows'  
FROM `user` 
    LEFT JOIN user_profile ON `user`.userid = user_profile.`user`
    LEFT JOIN `profile` ON user_profile.`profile` = `profile`.profile_id  
WHERE          status IN (0, 1) 
GROUP BY `user`.userid
HAVING GROUP_CONCAT(profile_name SEPARATOR ', ') LIKE '%root%'

答案 1 :(得分:0)

您有一个不寻常的查询,其中计数将返回0或1.您可以通过使用子查询来解决此问题:

SELECT COUNT(*) AS 'all_rows'  
FROM (SELECT GROUP_CONCAT(profile_name SEPARATOR ', ') as pns
      FROM `user` LEFT JOIN
           user_profile
           ON `user`.userid = user_profile.`user` LEFT JOIN
           `profile`
           ON user_profile.`profile` = `profile`.profile_id
      WHERE status IN (0, 1) 
     ) t
WHERE pns LIKE '%root%';

您还可以通过将逻辑移至where子句来解决问题:

SELECT COUNT(*)
FROM `user` LEFT JOIN
     user_profile
     ON `user`.userid = user_profile.`user` LEFT JOIN
     `profile`
     ON user_profile.`profile` = `profile`.profile_id
WHERE status IN (0, 1) and profile_name like '%root%';

答案 2 :(得分:0)

我喜欢解决方案: 这是记录计数查询的外观:

SELECT COUNT(*) AS 'all_rows' 
FROM (SELECT 
         userid AS 'User id', 
         login AS 'User name',    
         GROUP_CONCAT(profile_name SEPARATOR ', ') AS 'Profile(s)', 
         status  
      FROM `user` LEFT JOIN user_profile ON `user`.userid = user_profile.`user` 
            LEFT JOIN `profile` ON user_profile.`profile` = `profile`.profile_id  
      HAVING 
          status IN (0,    1) 
          AND  GROUP_CONCAT(profile_name SEPARATOR ', ') LIKE '%root%') t

这是主要问题:

SELECT 
    userid AS 'User id', 
    login AS 'User name', 
    GROUP_CONCAT(profile_name SEPARATOR ', ') AS 'Profil(ok)', 
    status  
FROM `user` LEFT JOIN user_profile ON `user`.userid = user_profile.`user`
            LEFT JOIN `profile` ON user_profile.`profile` = `profile`.profile_id  
HAVING 
    status IN (0, 1) 
    AND  GROUP_CONCAT(profile_name SEPARATOR ', ') LIKE '%root%'  
ORDER BY reg_date ASC 
LIMIT 0 ,10

我必须在任何地方使用HAVING而不是WHERE,因为我说主要查询是以编程方式生成的。这是我在SELECT部分​​中设置列的方法:

$listObj->setColumns(array('userid' => 'User id',
               'login'  => 'User name',
               'GROUP_CONCAT(profile_name SEPARATOR \', \')' => 'Profile(s)'));

当用户在引用GROUP_CONCAT(profile_name SEPARATOR ', ') AS 'Profile(s)'列的过滤器输入中键入%root%表达式时,我无法确定GROUP_CONCAT(profile_name SEPARATOR ', ') LIKE %root%部分是WHERE部分还是HAVING因为它与任何其他列一起处理(比如 userid AS 'User id'login AS 'User name'列)

剩下的技术问题是在任何地方使用HAVING都是错误的,即使简单的WHERE就足够了吗?