SQL按多值字符串列中的不同值分组

Posted

技术标签:

【中文标题】SQL按多值字符串列中的不同值分组【英文标题】:SQL grouping by distinct values in a multi-value string column 【发布时间】:2019-03-25 01:49:14 【问题描述】:

(我想根据具有多个值的字符串列中的不同值执行分组

该列有一个标准格式的字符串列表,用逗号分隔。潜在值仅为a,b,c,d

例如列collection(类型:字符串)包含:

Row 1: ["a","b"]
Row 2: ["b","c"]
Row 3: ["b","c","a"]
Row 4: ["d"]`

预期的输出是唯一值的计数:

collection | count
a | 2
b | 3
c | 2
d | 1

【问题讨论】:

请用您正在使用的数据库标记您的问题并描述collection的数据类型。 【参考方案1】:

对于以下所有内容,我都使用了这张表:

create table tmp (
 id INT auto_increment,
 test VARCHAR(255),
 PRIMARY KEY (id)
);

insert into tmp (test) values 
    ("a,b"),
    ("b,c"),
    ("b,c,a"),
    ("d")
;

如果可能的值只有a,b,c,d,您可以尝试以下方法之一: 请注意,这仅在您没有像testtest_new 这样相似的值时才有效,因为这样test 也将与所有test_new 行合并,并且计数将不匹配

select collection, COUNT(*) as count from tmp JOIN (
    select CONCAT("%", tb.collection, "%") as like_collection, collection from (
        select "a" COLLATE utf8_general_ci as collection
        union select "b" COLLATE utf8_general_ci as collection
        union select "c" COLLATE utf8_general_ci as collection
        union select "d" COLLATE utf8_general_ci as collection
    ) tb
) tb1 
ON tmp.test LIKE tb1.like_collection
GROUP BY tb1.collection;

这会给你想要的结果

collection | count
    a      |   2
    b      |   3
    c      |   2
    d      |   1

或者你可以试试这个

SELECT 
   (SELECT COUNT(*) FROM tmp WHERE test LIKE '%a%') as a_count,
   (SELECT COUNT(*) FROM tmp WHERE test LIKE '%b%') as b_count,
   (SELECT COUNT(*) FROM tmp WHERE test LIKE '%c%') as c_count,
   (SELECT COUNT(*) FROM tmp WHERE test LIKE '%d%') as d_count
;

结果会是这样的

a_count | b_count | c_count | d_count
2       |    3    |   2     |   1

【讨论】:

【参考方案2】:

您需要做的是首先将集合列分解成单独的行(如flatMap 操作)。在redshift中,生成新行的唯一方法是JOIN - 所以让我们CROSS JOIN你的输入表带有一个具有连续数字的静态表,并且只取id小于或等于的表集合中的元素数量。然后我们将使用split_part 函数读取正确索引处的项目。一旦我们有了 exploaded 表,我们将做一个简单的GROUP BY

如果您的项目存储为 JSON 数组字符串 ('["a", "b", "c"]'),那么您可以分别使用 JSON_ARRAY_LENGTHJSON_EXTRACT_ARRAY_ELEMENT_TEXT 而不是 REGEXP_COUNTSPLIT_PART

with 
    index as (
        select 1 as i 
        union all select 2 
        union all select 3 
        union all select 4 -- could be substituted with 'select row_number() over () as i from arbitrary_table limit 4'
    ), 
    agg as (
        select 'a,b' as collection
         union all select 'b,c'
         union all select 'b,c,a'
         union all select 'd'
    )
    select 
        split_part(collection, ',', i) as item,
        count(*)
    from index,agg
    where regexp_count(agg.collection, ',') + 1 >= index.i -- only get rows where number of items matches
    group by 1

【讨论】:

以上是关于SQL按多值字符串列中的不同值分组的主要内容,如果未能解决你的问题,请参考以下文章

为啥即使指定了所有值,Spark SQL 也会为字符串列打开可为空?

Pandas 数据框:如何按多值列将一行拆分为多行? [复制]

Spark将布尔列与字符串列进行比较与比较值相等的int和字符串的工作方式不同

如何检查 SQL Server 2008 表中字符串列中的 id

使用 SQL 将字符串列转换为 mongodb 中的日期时间

在字符串列上使用 GROUP BY 时未获得分组结果