sql对多个类别中的项进行计数并对丢失的项进行分组,总计为0

i7uaboj4  于 2021-07-26  发布在  Java
关注(0)|答案(2)|浏览(307)

我在bigquery中有一个表,我想聚合多个不同的类别(表中的列)来生成数据摘要,这是一个简单的count和groupby语句。然而,对于这个项目,我想产生一个“完整”的计数,每一个类别的排列(类别的可能值是已知的提前时间)与0总组合没有任何项目的排列。
下面是简单的初始计数和组语句:

SELECT
  COUNT(item.id) as total,
  TIMESTAMP_TRUNC(item.date, WEEK) as week,
  item.attribute_1,
  item.attribute_2,
FROM item
GROUP BY week, attribute_1, attribute_2
ORDER BY week DESC, attribute_1, attribute_2

哪里 attribute_1 有可能的值 ('A', 'B', 'C') 以及 attribute_2 有可能的值 ('X', 'Y', 'Z') 会产生这样的结果:

Row | total | week                    | attribute_1 | attribute_2
-----------------------------------------------------------------
1   | 1     | 2020-07-12 00:00:00 UTC | A           | X
2   | 2     | 2020-07-12 00:00:00 UTC | A           | Z
3   | 1     | 2020-07-12 00:00:00 UTC | B           | X
4   | 1     | 2020-07-12 00:00:00 UTC | B           | Y
5   | 3     | 2020-07-12 00:00:00 UTC | B           | Z
6   | 1     | 2020-07-12 00:00:00 UTC | C           | Y
7   | 1     | 2020-07-12 00:00:00 UTC | C           | Z
etc.

然而,我的目标是最终得到这样的结果:

Row | total | week                    | attribute_1 | attribute_2
-----------------------------------------------------------------
1   | 1     | 2020-07-12 00:00:00 UTC | A           | X
2   | 0     | 2020-07-12 00:00:00 UTC | A           | Y
3   | 2     | 2020-07-12 00:00:00 UTC | A           | Z
4   | 1     | 2020-07-12 00:00:00 UTC | B           | X
5   | 1     | 2020-07-12 00:00:00 UTC | B           | Y
6   | 3     | 2020-07-12 00:00:00 UTC | B           | Z
7   | 0     | 2020-07-12 00:00:00 UTC | C           | X
8   | 1     | 2020-07-12 00:00:00 UTC | C           | Y
9   | 1     | 2020-07-12 00:00:00 UTC | C           | Z
etc.

对于单个类别,我发现了类似的问题,因此我可以通过以下语句保持其他属性不变来解决该问题:

WITH data AS (
  SELECT
    item.id as item_id,
    TIMESTAMP_TRUNC(item.date, WEEK) as week,
    item.attribute_1,
    item.attribute_2,
  FROM item
  GROUP BY week, attribute_1, attribute_2
  ORDER BY week DESC, attribute_1, attribute_2
),
category_1 as (
 select 'A' as name union all
 select 'B' union all
 select 'C'
)
SELECT
  category_1.name,
  (
    SELECT COUNT(item_id) as total
    FROM data
    WHERE data.attribute_1 = category_1.name
    AND data.attribute_2 = 'X'
    AND data.week > TIMESTAMP('2020-07-10')
  ) as total
FROM category_1

产生:

Row | name | total
------------------
1   | A    | 1
2   | B    | 1
3   | C    | 0

我感兴趣的一般情况能解决吗?

ckx4rj1h

ckx4rj1h1#

如果我理解正确,您可以使用 cross join 然后与现有值匹配:

SELECT COALESCE(SUM(i.total), 0) as total,
       w.week, a1.attribute_1, a2.attribute_2
FROM (SELECT distinct TIMESTAMP_TRUNC(date, WEEK) as week FROM item) w CROSS JOIN
     (SELECT distinct attribute_1 FROM item) a1 CROSS JOIN
     (SELECT distinct attribute_2 FROM item) a2 LEFT JOIN   
     item i
     ON TIMESTAMP_TRUNC(i.date, WEEK) = w.week AND
        i.attribute_1 = a1.attribute_1 AND
        i.attribute_2 = a2.attribute_2
GROUP BY w.week, a1.attribute_1, a2.attribute_2
ORDER BY week DESC, attribute_1, attribute_2;

这是一把小提琴。它使用postgres,因此postgres有一些语法调整。

x0fgdtte

x0fgdtte2#

下面是bigquery标准sql


# standardSQL

WITH totals AS (
  SELECT
    COUNT(item.id) as total,
    TIMESTAMP_TRUNC(item.date, WEEK) AS week,
    item.attribute_1,
    item.attribute_2,
  FROM item
  GROUP BY week, attribute_1, attribute_2
), dict AS (
  SELECT 
    ARRAY_AGG(DISTINCT TIMESTAMP_TRUNC(date, WEEK)) AS weeks,
    ARRAY_AGG(DISTINCT attribute_1) AS attributes_1,
    ARRAY_AGG(DISTINCT attribute_2) AS attributes_2
  FROM item
)
SELECT IFNULL(total, 0) total, week, attribute_1, attribute_2
FROM dict, dict.weeks AS week, dict.attributes_1 AS attribute_1, dict.attributes_2 AS attribute_2
LEFT JOIN totals
USING(week, attribute_1, attribute_2)
-- ORDER BY week DESC, attribute_1, attribute_2

如你所见cte total 是你的原始查询,下一个cte dict 建立了周和属性的字典,其余的只是交叉连接,产生周和属性的每一个排列,然后在总数上连接

相关问题