【问题标题】:Aggregate SQL group by counts based on group by基于 group by 聚合 SQL group by 计数
【发布时间】:2013-09-13 18:54:56
【问题描述】:

我有一个这样的查询(它不能按预期工作)

SELECT 
(CASE 
    WHEN str LIKE '%some_string%' THEN 's'
    WHEN str LIKE '%some_string2%' THEN 's2'
END) as str,
COUNT(*) as num FROM Table WHERE
str LIKE '%some_string%' or
str LIKE '%some_string2%'
group by str

并且表格包含类似的东西

|      str                       |
|------------------------------- |
| "some_string_a;"               |  
| "some_string_b; some_else"     |  
| "some_string_c; some_else"     |  
| "some_else; some_string2a"     |  
| "some_string_c; some_string2b" |  

如何获得如下结果?

|      str      |   num  |
|---------------|--------|
| s             |   4    |
| s2            |   2    |

我目前低估了,因为当第 1、2、3 和 5 行实际上包含两者时,它们被计为“some_string%”(因此也被计为“s”)。

【问题讨论】:

  • 我不认为你可以做到这一点而不使 非常 变得复杂 - 让值返回列而不是行是否可以接受?除非您绝对需要这样做,否则对于所需的工作量来说,这可能是一个很好的结果。
  • @rio 你能检查我的答案吗??
  • 你必须首先规范你的数据。
  • @eouw0o83hf 我认为这是奥尔登的方法,对吗?
  • @Rio 是的。如果这是一个可以接受的回应,那会让你更轻松。

标签: sql group-by case


【解决方案1】:

我的更新答案

SQL Fiddle

试试这个

    CREATE table Table1 (str varchar(50));


    Insert into Table1(str) values('aaa');
    Insert into Table1(str) values('bbb');
    Insert into Table1(str) values('aaaaaaaaaa');
    Insert into Table1(str) values('bbbbbbbbbb');
    Insert into Table1(str) values('aaaaaaaaaaaaaaaa');
    Insert into Table1(str) values('aaabbbbb');
    Insert into Table1(str) values('ccccccccccccccc');


Select str , count(*) from
(
    SELECT 
    (CASE  
    WHEN str LIKE '%bbb%' THEN 's2'
    WHEN str LIKE '%aaa%' THEN 's'     
    END) as str
    FROM Table1 WHERE
    str LIKE '%aaa%' or
    str LIKE '%bbb%'
) as T group by str; -- will count in s2 means in a so s will be 3 and s2 is 3

【讨论】:

  • Insert into Table1(str) values('aaabbbbb');
  • of 如果我插入 aaabbbb,它应该在 s 或 s2 中计数 .. 我认为按照你的说法,它应该在 s2 中计数,所以在我的示例中这两个值都是 3(在插入 aaabbbb 之后)..对吧??
  • 应该都是3,但是你的SQLFiddle返回3和2(把第一行改成aaabbbbb)
  • 我觉得aaa应该算4次吧?
  • 你的意思是 s 是 4 而 s2 是 3 吗?在那种情况下,奥尔登的回应是我认为的唯一方式
【解决方案2】:

尝试在 CASE 语句中切换条件的顺序。

SELECT 
(CASE 
    WHEN str LIKE '%some_string2%' THEN 's2'
    WHEN str LIKE '%some_string%' THEN 's'
END) as str,
COUNT(*) as num FROM Table WHERE
str LIKE '%some_string%' or
str LIKE '%some_string2%'
group by str

【讨论】:

  • 我不认为它可以处理“单行中的 some_string 的两个实例”的情况 - 这是我最初的想法:p
  • 它不会在一行中处理 some_string 的两个实例,你是对的。但它确实解决了当它应该向 s2 移动时对单词 s 进行行计数的问题。为了处理您提出的问题,我可能会创建一个 UDF,它返回一个模式在另一个字符串/行中出现的次数的整数。然后我们可以对这些求和。
【解决方案3】:

你可以这样做。

SELECT SUM(IF(str LIKE '%some_string%',1,0)) AS s,
       SUM(IF(str LIKE '%some_string2%',1,0)) AS s2
FROM Table WHERE
str LIKE '%some_string%' or
str LIKE '%some_string2%'
group by str;

【讨论】:

  • 我认为这会创建额外的列,但我想我必须按 s、s2 排序,而且我事先不知道哪些列更像s2,s 更好)。
【解决方案4】:

您想按select 中的相同表达式进行分组:

SELECT (CASE WHEN str LIKE '%some_string%' THEN 's'
             WHEN str LIKE '%some_string2%' THEN 's2'
        END) as str,
       COUNT(*) as num
FROM Table
WHERE str LIKE '%some_string%' or
      str LIKE '%some_string2%'
group by (CASE WHEN str LIKE '%some_string%' THEN 's'
               WHEN str LIKE '%some_string2%' THEN 's2'
          END);

某些数据库允许在 group by 中使用列别名 (str),但不是全部。使用完整表达式或使用子查询(如 Dhaval 所建议)会更安全。但是,我会把它写成:

select str, count(*)
from (select (CASE WHEN str LIKE '%some_string%' THEN 's'
                   WHEN str LIKE '%some_string2%' THEN 's2'
              END) as str
      from table
     ) t
where str is not null
group by str;

您不必重复比较,因为str 在两者都不匹配时会得到NULL 值。

【讨论】:

  • 我在分组时遇到问题 (CASE WHEN str LIKE '%some_string%' THEN 's' WHEN str LIKE '%some_string2%' THEN 's2' END);少量。我需要按 str 进行分组,但是按 (CASE WHEN str LIKE '%some_string%' THEN 's' WHEN str LIKE '%some_string2%' THEN 's2' END) 分组,因为 str 似乎玩得不好。
  • 什么麻烦?你使用的是什么数据库?这是标准的 ANSI 语法。
【解决方案5】:

使用 Postgresn 模式的一般解决方案可能如下所示:

SELECT p.pattern, count((str1 LIKE '%' || p.pattern || '%') OR NULL) AS  ct
FROM  (
   SELECT regexp_split_to_table(str, ';') AS str1
   FROM tbl
   ) x
CROSS  JOIN (
   VALUES ('some_string')
         ,('some_string2')
         -- more?
   ) AS p(pattern)
GROUP  BY p.pattern

结果:

pattern       | ct
--------------+----
some_string   | 6
some_string2  | 2

-> SQLfiddle demo

  • 假设您想要匹配字符串的每个部分,由; 分隔。 Postgres 函数regexp_split_to_table() 以这种方式规范化您的数据。

  • 我还假设您希望计算具有任何模式的每个匹配,并且在第一个匹配后不停止。

CASE 语句只会产生一个匹配项并抑制其余的匹配项。所以我假设你确实想要那个。

相反,我交叉连接到一个VALUES 表达式,它提供了你想要的任意数量的模式。一般使用非常方便。您可以使用表或子查询来提供模式来代替 VALUES 表达式。

【讨论】:

  • 这是一个优雅的解决方案,但不幸的是数据实际上并不是那么干净,所以 ;假设实际上不成立。不过谢谢!
  • 我只能按照给出的问题来回答。
猜你喜欢
  • 2014-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-24
  • 2014-11-22
  • 2012-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多