假设我有一个名为t的表,其中有两列foobar.

foo bar
1 11
1 11
2 11
2 11
2 11
3 11
3 12
3 12

现在我想分别计算foobar的不同值的出现次数,并将它们聚合到ARRAY<MAP<BIGINT, BIGINT>>中.

在本例中:

  • foo == 1例出现2次;
  • foo = 2例出现3次;
  • foo = 3例出现3次;
  • bar == 11次出现6次;
  • bar == 12出现2次.

因此,结果表应该如下所示:

name cnt
"foo" [{1:2}, {2:3}, {3:3}]
"bar" [{11:6}, {12:2}]

我目前的做法有点像这样:

WITH t_foo AS (
  SELECT
    "foo" AS name,
   COLLECT_LIST(MAP(val, cnt)) AS cnt
  FROM (
    SELECT
      foo AS val,
      COUNT(*) AS cnt
    FROM
      t
    GROUP BY
      foo
  ) AS tt
),
t_bar AS (
  SELECT
    "bar" AS name,
   COLLECT_LIST(MAP(val, cnt)) AS cnt
  FROM (
    SELECT
      bar AS val,
      COUNT(*) AS cnt
    FROM
      t
    GROUP BY
      bar
  ) AS tt
)
SELECT * FROM t_foo
UNION ALL 
SELECT * FROM t_bar

这是可行的,但似乎是重复性的.事实上,我不仅有foo个和bar个专栏要处理,还有十几个其他专栏要处理.有没有更聪明的方法来解决这个问题?

推荐答案

为了泛化这段代码,您应该需要动态查询,但是这种方法可能会很繁重,并且容易受到SQL注入攻击.

然而,您仍然可以在不使用动态查询的情况下执行某些操作,即:

  • 使用窗口函数而不是聚合,一次计算所有计数
  • 应用联合所有的COLLECT_LIST个操作.
WITH cte AS (
    SELECT DISTINCT foo, COUNT(*) OVER(PARTITION BY foo) AS cnt_foo,
                    bar, COUNT(*) OVER(PARTITION BY bar) AS cnt_bar
    FROM t
)
SELECT "foo" AS name, COLLECT_LIST(MAP(foo, cnt_foo)) AS cnt FROM cte
UNION ALL 
SELECT "bar" AS name, COLLECT_LIST(MAP(bar, cnt_bar)) AS cnt FROM cte

应该会比原来的表现更好.

Sql相关问答推荐

在postgresql中使用来自另一个字段的日期名称作为JSONB查询中的关键字

Postgresql:从jsons数组到单个id索引的json

SQL—如何在搜索的元素之后和之前获取元素?

Select 最大值,但当并列时,从其他列 Select 最大值

有没有一种正确的方法来利用SQL UNION来从三个潜在查询中 Select 最大值?

如何连接第二个表并将其内容输入到第一个表的单个字段中?

LEFT JOIN不显示计数0我期望的方式

更新PostgreSQL 15中的JSON值

一个SQL查询将在需要的地方多次返回同一成员

防止ActiveRecord迁移在db/structure.sql中进行巨大更改

如何查找所提供日期范围的所有季度开始日期和结束日期

基于多参数的SQL Server条件过滤

根据开始日期和结束日期的差异计算每天的计费

Oracle PL/SQL:解决DBMS输出大小限制的问题

排除具有部分匹配条件的记录

在Power Bi中将SQL代码转换为DAX

为 sqlite 全文搜索 (fts) 创建触发器时出现虚拟表的不安全使用

我如何编写一个遍历数组数组并将所有值连接成一个字符串的 postgres 函数

计算 SQL 中的总体成功率:递归 CTE 还是替代方法?

Select 给定类别列表(或更多类别)中的所有事物