如何在 ANSI SQL 中完成 "cascading grouping" 列?

How do I accomplish "cascading grouping" of columns in ANSI SQL?

我有一个 Presto SQL table 看起来像这样:

|tenant|type|environment                                    |
|                                                           |
| X    | A  |http:a.b.c(foo)/http:a.b.c(bar)/http:a.b.c(baz)|
| X    | A  |http:d.e.f(foo)/http:d.e.f(bar)/http:d.e.f(baz)|
| X    | A  |http:g.h.i(foo)                                |
| X    | B  |http:g.h.i(foo)/http:g.h.i(bar)                |

所有列的类型都是字符串。 我需要生成计算每个租户和类型的每种环境类型(foo、bar 或 baz)的输出。 IE。上面的数据应该像这样列出:

X A foo 3
    bar 2
    baz 2
X B foo 1
    bar 1

我一直在尝试这样的查询:

SELECT "tenant_id", "type_id", "environment", count(*) AS total_count 
FROM "tenant_table"    
WHERE "environment" LIKE '%foo%' 
GROUP BY "tenant_id", "type_id", "environment";

但是我没有得到我需要的输出。我在更改数据类型方面确实有一点灵活性。数据最初来自 CSV 文件。例如,如果将“环境”列的类型重新定义为数组之类的类型会使事情变得更容易,那么这是一个选项。解决此问题的任何帮助将不胜感激。谢谢。

如果这是一个固定的值列表,每个字符串最多出现 1 次,您可以将其放入派生 table 并使用 like 搜索匹配项:

select t.tenant, t.type, v.val, count(*) cnt
from tenant_db t
inner join (values ('foo'), ('bar'), ('baz')) v(val)
    on t.environment like '%' || v.val || '%'
group by t.tenant, t.type, v.val

根据您的要求,您可能希望缩小搜索条件以避免误报;也许使用括号:

on t.environment like '%(' || v.val || ')%'

或者使用正则表达式。

您可以使用 regexp_extract_all and use UNNEST 提取值以在计算聚合之前“展平”结果数组:

WITH data(tenant, type, environment) AS (
    VALUES
        ('X', 'A', 'http:a.b.c(foo)/http:a.b.c(bar)/http:a.b.c(baz)'),
        ('X', 'A', 'http:d.e.f(foo)/http:d.e.f(bar)/http:d.e.f(baz)'),
        ('X', 'A', 'http:g.h.i(foo)'),
        ('X', 'B', 'http:g.h.i(foo)/http:g.h.i(bar)')
)
SELECT tenant, type, value, count(*)
FROM data, UNNEST(regexp_extract_all(data.environment, '\(([^\)]+)\)', 1)) t(value)
GROUP BY tenant, type, value

产生:

 tenant | type | value | _col3
--------+------+-------+-------
 X      | A    | baz   |     2
 X      | A    | bar   |     2
 X      | A    | foo   |     3
 X      | B    | bar   |     1
 X      | B    | foo   |     1