Mysql - 条件组

时间:2014-07-18 17:20:51

标签: mysql group-by case having

我试图一起使用CASE和GROUP BY来有条件地过滤结果,只要它们符合CASE标准,如果它们不相同,则返回结果,好像没有指定GROUP BY标准。

这是我所拥有的简单模型:

es.id | es.acct_num | p.id | p.name
1001  | 4306-0      | 1569 | The High School
1002  | 4306-0      | 1569 | The High School
665   | 5906-7      | 981  | Rec Center
783   | 5906-7      | 1221 | The Gym

以及我希望看到的内容:

es.id | es.acct_num | p.id | p.name
1001  | 4306-0      | 1569 | The High School
1002  | 4306-0      | 1569 | The High School
0     | 5906-7      | 0    | MULTI-SITE

由于es.acct_num 5906-7 有超过1个不同的关联p.id,我希望它按es.acct_num分组为1行项,然后有es.id,p .id由' 0'表示,并且p.name由字符串' MULTI-SITE'表示。

但是,由于es.acct_num 4306-0 只有1个不同的关联p.id,我希望这些都作为单独的行项返回,就像没有应用分组条件一样。

解决方案逃脱了我。我怎么能做到这一点?

3 个答案:

答案 0 :(得分:3)

您可以使用条件聚合执行此操作:

SELECT (case when count(*) > 1 then 0 else max(es.id) end) as esid,
       es.acct_num,
       (case when count(*) > 1 then 0 else max(p.id) end) as pid,
       (case when count(*) > 1 then 'MULTI-SITE' else p.name end) as name,
       COUNT(*) AS cnt
FROM es join
     p
     on . . . 
GROUP BY es.acct_num;

不要被max()表达式所迷惑。 case的那一部分只有一行,因此这些行只返回该行中的值。

编辑:

我认为您需要使用相关子查询,连接/聚合或使用变量计算值来执行此操作。使用窗口函数,几乎任何其他数据库都会更容易。这是一个想法,在没有看到完整查询的情况下,有点难以详细表达:

SELECT (case when esp.cnt > 1 then 0 else max(es.id) end) as esid,
       es.acct_num,
       (case when esp.cnt > 1 then 0 else max(p.id) end) as pid,
       (case when esp.cnt > 1 then 'MULTI-SITE' else p.name end) as name
FROM es join
     p
     on . . .  join
     (select es.acct_num, count(distinct p.id) as cnt
      from . . .
      group by es.acct_num
     ) esp
     on esp.acct_num = es.acct_num
GROUP BY es.acct_num, (case when cnt = 0 then es.id end);

答案 1 :(得分:3)

很抱歉这个延误了。

我确定的解决方案似乎是两个想法的混合体。 2个查询之间的UNION,其中嵌套了一个子查询,该查询首先充当过滤器以排除“MULTI-SITE”结果,在第二种情况下仅包括这些结果:

SELECT col1,col2,etc... from table WHERE acct_num NOT IN (

SELECT MULTISITE.es_acct_num FROM (
SELECT acct_num as es_acct_num,
       COUNT(DISTINCT p.id) as `cnt`
FROM blah, blah, blah
GROUP BY es.acct_num HAVING `cnt` > 1) as MULTISITE)

UNION

SELECT col1,col2,etc... from table WHERE acct_num IN (

SELECT MULTISITE.es_acct_num FROM (
SELECT acct_num as es_acct_num,
       COUNT(DISTINCT p.id) as `cnt`
FROM blah, blah, blah
GROUP BY es.acct_num HAVING `cnt` > 1) as MULTISITE)
GROUP BY es.acct_num -- notice this final group by clause sitting outside the "filter" rolls the multi-site results up into their respective groupings by acct_num

这两个回复都包含了很好的想法,但我提出的解决方案是两个想法的组合,所以我觉得最好将我正在使用的解决方案标记为正确答案。但是,由于我发现它们都非常有用,我上面的答案仍然是+1。

答案 2 :(得分:2)

您可以将其分为两个单独的查询,并使用UNION加入所有内容:

SELECT es.id, es.acct_num, p.id, p.name, COUNT(p.id) AS count
FROM ... es JOIN ... p
GROUP BY es.acct_num
HAVING count > 1

UNION

SELECT 0 AS es.id, es.acct_num, 0 AS p.id, 'MULTI-SITE' AS p.name, COUNT(p.id) AS count
FROM ... es JOIN ... p
GROUP BY es.acct_num
HAVING count = 0