如何使用 MySQL 表示分区上的组计数
Posted
技术标签:
【中文标题】如何使用 MySQL 表示分区上的组计数【英文标题】:How to represent group counts over a partition using MySQL 【发布时间】:2021-07-01 18:12:32 【问题描述】:一段时间以来一直在摸索这个问题,所以我的数据看起来像这样:
USER GROUP DATE
001 AA 02-20-21
007 AA 02-20-21
002 DD 02-20-21
003 DD 02-21-21
004 BB 02-21-21
018 BB 02-22-21
005 AA 02-22-21
006 EE 02-22-21
022 AA 02-22-21
就目前而言,我将这些数据汇总如下:
DATE GROUP USER_COUNT NEW_USER_COUNT
02-20-21 AA 2 2
02-20-21 DD 1 1
02-21-21 DD 2 1
02-21-21 BB 1 1
02-22-21 BB 2 1
02-22-21 AA 4 2
02-22-21 EE 1 1
这样做的目的是让我获得每个单独组的用户计数,以及从组的最后一次迭代到下一次迭代的新用户计数。
现在这可以正常工作,但是有一个关键问题。出于可视化目的,我需要在每个日期中表示每个组。就目前而言,如果一个组没有出现在某个日期,它就不会显示;我需要每个组出现在每个日期,所以如果我们在给定日期没有用户,我们会使用以前的 user_count 没有新用户。
这就是我希望上述数据的外观:
DATE GROUP USER_COUNT NEW_USER_COUNT
02-20-21 AA 2 2
02-20-21 DD 1 1
02-21-21 AA 2 0
02-21-21 DD 2 1
02-21-21 BB 1 1
02-22-21 AA 4 2
02-22-21 DD 2 0
02-22-21 BB 2 1
02-22-21 EE 1 1
请注意,在 AA 和 DD 出现之后,它们会继续出现在每个 DATE
上,即使它们没有增长,它们也会使用最后一个数字。
因此,基本上,在第一次出现新组后,它会在以后的每个日期出现。新组不固定,随时可能出现新组。
这是我现有的查询:
WITH NEW_USER AS (
SELECT USER,
DATE,
GROUP,
ROW_NUMBER() OVER (
PARTITION BY USER
ORDER BY DATE
) AS row_n
FROM dt
),
/*Increment count of unique users based on GROUP. */
CUMULATIVE_USER_COUNT AS (
SELECT DATE,
GROUP,
SUM(COUNT(*)) OVER (
PARTITION BY GROUP
ORDER BY DATE
) AS USER_COUNT,
COUNT(DISTINCT USER) AS NEW_USER_COUNT
FROM NEW_USER
WHERE row_n = 1
GROUP BY DATE,
GROUP
ORDER BY DATE,
GROUP
)
SELECT *
FROM CUMULATIVE_USER_COUNT
另外仅供参考,每行的 USER ID 不是唯一的,DISTINCT USER
是必需的。
【问题讨论】:
我还是不明白你是如何构造 NEW_USER_COUNT @nbk NEW_USER_COUNT 基本上是每天 USER_COUNT 组的差异。因此,当 DD 第一次出现在 2/20/21 时,它是 1,因为 1+0 = 1(用户计数)。然后当 DD 在 2/21/21 再次出现时,我们得到 2 表示 USER_COUNT 和 1 表示 NEW_USER_COUNT。 (2/20/21 来自 USER_COUNT 的 1 个 + 1 = 2/21/21 的 2 个 USER_COUNT。有意义吗? 请澄清您的示例数据 -02-20-21
在 mysql 中不是合法的 DATE 值。
更复杂的是必须添加缺少的日期,这使得查询更加复杂,此外我必须使用 ST_TO_DATE
【参考方案1】:
WITH
cte1 AS ( SELECT DISTINCT `DATE`
FROM test ),
cte2 AS ( SELECT DISTINCT `GROUP`
FROM test ),
cte3 AS ( SELECT `DATE`,
`GROUP`,
SUM(COUNT(test.USER)) OVER (PARTITION BY `GROUP` ORDER BY `DATE`) USER_COUNT,
COUNT(test.USER) NEW_USER_COUNT
FROM cte1
CROSS JOIN cte2
LEFT JOIN test USING (`DATE`, `GROUP`)
GROUP BY `DATE`, `GROUP` )
SELECT *
FROM cte3
WHERE USER_COUNT
ORDER BY `DATE`, `GROUP`
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=bb4c55ac8897c5f5dcc84c1267f080c0
【讨论】:
【参考方案2】:您可以使用cross join
生成行——使用一个扭曲来处理日期。然后引入现有数据:
select d.date, g.group,
count(dt.date) as num_on_day,
sum(count(dt.date)) over (partition by g.group order by d.date) as running_num
from (select distinct date
from dt
) d join
(select group, min(date) as min_date
from dt
group by group
) g
on d.date >= g.min_date left join
(select dt.*,
row_number() over (partition by group, user_id order by date) as seqnum
from dt
) dt
on dt.date = d.date and dt.group = g.group and dt.seqnum = 1
group by d.date, g.group;
【讨论】:
以上是关于如何使用 MySQL 表示分区上的组计数的主要内容,如果未能解决你的问题,请参考以下文章