mysql计算多路复用条目的多个出现次数

时间:2014-04-04 06:11:52

标签: mysql

我有一个如下所示的mysql表,

  id          reasonCode
------      ------------------
  1           0, 1
  2           0
  3           1, 2, 3
  4           2
  5           1, 0

我希望输出为

  reasonCode           occurrences

    0                      3
    1                      3
    2                      2
    3                      1

我试过" group by"但它给出了类似的东西。

  reasonCode           occurrences

    0, 1                   1
    0                      1
    1, 2, 3                1
    2                      1
    1, 0                   1

如果有人知道该怎么做,将不胜感激。

3 个答案:

答案 0 :(得分:1)

尝试此查询

SELECT Reason,COUNT(Reason) FROM
(
SELECT
  id,
  SUBSTRING_INDEX(SUBSTRING_INDEX(reasoncode, ',', n.digit+1), ',', -1) Reason
FROM
  table1
  INNER JOIN
  (SELECT 0 digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) n
  ON LENGTH(REPLACE(reasoncode, ',' , '')) <= LENGTH(reasoncode)-n.digit
ORDER BY
  id,
  n.digit
) T

Group By Reason;

<强> SQL FIDDLE

输出将是:

REASON  OCCURANCES
0           3
1           3
2           2
3           1

答案 1 :(得分:1)

  

...原因代码的数量将会改变。用户可以随时添加/删除原因代码......

如果原因代码的一部分未知,那么您最好生成查询动态。您可以通过存储过程执行此操作。

要遵循的步骤

  1. 将每个原因代码字符串提取到变量中。
  2. 拆分它以找到每个原因代码。
  3. 使用找到的代码生成select,其计数为1。
  4. Union all如果生成了一些这样的陈述。
  5. 循环,直到每个字符串中不再存在代码。
  6. 重复直到处理完所有行
  7. 现在,在生成的结果集组上运行聚合函数 原因代码。
  8. 你手头有结果。
  9. 示例代码段的一部分

    -- ...
    
    set @sql_query := 'select reason_code, sum(rc_count) as rc_count from (' ;
    set @sql_query := 
           concat( @sql_query, 
                   '\n  ( select null as reason_code, 0 as rc_count )' );
    
    -- ...
    
    splitting_reason_codes: loop
      set comma_position = locate( ',', reason_code_string );
      if comma_position then
        set rc := substring( reason_code_string, 1, comma_position-1 );
        set reason_code_string := 
                substring( reason_code_string, comma_position+1 );
      else
        set rc := reason_code_string;
      end if;
    
      if length( rc ) > 0 then
        set @sql_query := 
                concat( @sql_query, 
                        '\n   union all ( select ', rc, ', 1 )' );
      end if;
    
      if ! comma_position then
        leave splitting_reason_codes;
      end if;
    end loop splitting_reason_codes;
    
    -- ...
    
    set @sql_query := concat( @sql_query, '\n) unique_reason_codes' );
    set @sql_query := concat( @sql_query, '\nwhere reason_code is not null' );
    set @sql_query := concat( @sql_query, '\ngroup by reason_code' );
    set @sql_query := concat( @sql_query, '\norder by reason_code' );
    
    prepare stmt from @sql_query;
    execute stmt;
    

    演示 @ SQL Fiddle

答案 2 :(得分:0)

如果你有一张原因代码表(我假设你这样做,所以你知道原因代码1的意思是什么),那么你可以这样做: -

SELECT a.id, COUNT(b.id)
FROM reason_codes a
LEFT OUTER JOIN id_reason_code b
ON FIND_IN_SET(a.id, b.reasonCode)
GROUP BY a.id

然而,一个问题是你的逗号后面有空格。逗号分隔字段在最好的时候是一个问题(最好分成另一个表的多行 - 如果需要的话,很容易将它们连接在一起),但逗号后面的空格会产生问题(注意删除这些空格)也会让@Vignesh Kumar的解决方案更简单一些。)

为了解决这个问题,你可以这样做: -

SELECT a.id, COUNT(b.id)
FROM reason_codes a
LEFT OUTER JOIN id_reason_code b
ON FIND_IN_SET(a.id, REPLACE(b.reasonCode, ' ', ''))
GROUP BY a.id

编辑 - 解释

这只是一个LEFT OUTER JOIN。这将占用第一个表中的每一行(即原因代码),并将其与第二个表上匹配的任何行匹配(即,ie_reason_code - 不确定您在上面显示的表格被调用);如果第二个表上没有匹配的行,那么第一个表中的行仍会被带回,但第二个表的列中为NULL。在这种情况下,连接基于FIND_IN_SET完成。这将查找逗号分隔值列表中的第一个参数,并在找到时返回位置(因此,如果发现它的计算结果为true)。

然后,COUNT / GROUP BY计算每个a.id的b.id值的数量并显示该数量。

第二个查询正在执行相同的操作,但它在检查值之前从逗号分隔列表中删除任何空格(当您有空格时需要以及将值分隔开的逗号)。

如果您有以下表格: -

reason_codes table
id  reason
0   Reason A
1   Reason B
2   Reason C
3   Reason D
4   Reason E

id_reason_code table
id          reasonCode
1           0,1
2           0
3           1,2,3
4           2
5           1,0

然后是以下sql(删除COUNT / GROUP BY): -

SELECT a.id, b.id
FROM reason_codes a
LEFT OUTER JOIN id_reason_code b
ON FIND_IN_SET(a.id, b.reasonCode)

将提供以下内容: -

a.id    b.id
0       1
0       2
0       5
1       1
1       3
1       5
2       3
2       4
3       3
4       NULL

运行: -

SELECT a.id, COUNT(b.id)
FROM reason_codes a
LEFT OUTER JOIN id_reason_code b
ON FIND_IN_SET(a.id, b.reasonCode)
GROUP BY a.id

COUNT / GROUP BY为a.id的每个值赋予一行,然后为a.id的值为b.id的值(非null)计数: -

a.id    count(b.id)
0       3
1       3
2       2
3       1
4       0

如果您愿意,也可以带回实际原因而不是代码: -

SELECT a.id, a.reason, COUNT(b.id)
FROM reason_codes a
LEFT OUTER JOIN id_reason_code b
ON FIND_IN_SET(a.id, b.reasonCode)
GROUP BY a.id, a.reason

,并提供: -

a.id    a.reason    count(b.id)
0       Reason A    3
1       Reason B    3
2       Reason C    2
3       Reason D    1
4       Reason E    0