SQL - 每个月采样 n 个用户
SQL - sample n users for each month
我目前正在使用具有属性(user_id
、created_at
、...)的 table。我想对自去年 11 月以来每个月创建的 100 到 200 个用户进行抽样。如果我一个月内只 select 100 个用户,那会很容易,因为我可以这样做:
select * from TABLE where created_at >= 'xxxx' and created_at <= 'xxxx'
但我想不出一个干净的方法来为每个月执行此操作,然后将结果放在一起。这有可能以任何方式用 SQL 实现吗?非常感谢。
使用ROW_NUMBER
:
SELECT user_id, created_at -- and other columns
FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY DATE_FORMAT(created_at, '%Y %m')
ORDER BY created_at DESC) rn
FROM yourTable
) t
WHERE t.rn <= 100 AND created_at >= '2017-11-01';
我们使用MySQL函数DATE_FORMAT
创建每个月和年的分区,然后我们只保留每个分区的100个用户。
如果你的日期真的存储为字符串2018-01-01
,那么你可以取字符串的前 7 个字符来获取月份。
然后,使用ROW_NUMBER
按月划分,每个月选取前100名用户。
SELECT
user_id,
created_at
FROM
(
SELECT
user_id,
created_at,
ROW_NUMBER() OVER (PARTITION BY substr(created_at, 1, 7) ORDER BY user_id) AS rn
FROM T
WHERE created_at >= '2017-11-01'
) AS R
WHERE
rn <= 100
;
ORDER BY
定义选择哪些用户。上面的查询根据 ID 选择前 100 位用户,这很可能是按照他们创建的顺序,因此查询基本上选择了每个月创建的前 100 位用户。
如果您想要一些随机选择,则按 returns 随机数的函数排序。这看起来更像是 "sample".
SELECT
user_id,
created_at
FROM
(
SELECT
user_id,
created_at,
ROW_NUMBER() OVER (PARTITION BY substr(created_at, 1, 7) ORDER BY random()) AS rn
FROM T
WHERE created_at >= '2017-11-01'
) AS R
WHERE
rn <= 100
;
假设 t-sql 和 created_at 是日期时间。
您可以使用 ROW_NUMBER() (取决于您可以使用几个不同的 rank/row 类型函数之后的特定行为)为每个 year/month 组合生成一个行号。
https://docs.microsoft.com/en-us/sql/t-sql/functions/row-number-transact-sql?view=sql-server-2017
Declare @rows int = 100,
@date datetime = '2017-11-30'
SELECT *
FROM [YourTable] t
WHERE EXISTS (
SELECT *
from(
Select user_id,
ROW_NUMBER()OVER(PARTITION BY DATEPART(YEAR, created_at), DATEPART(MONTH, created_at) ORDER BY created_at) as rn
FROM [YourTable]
WHERE created_at > @date
) as ds
Where rn <= @rows
and ds.user_id = t.user_id
)
编辑:在指定 rdbms 之前写的,除非不合适,否则我会把它留在这里以防其他人偶然发现。
这里有一篇关于使用 NTILE 和 TABLESAMPLE 的博客,我认为这正是您在这里需要的(分层恒定比例采样)。
我目前正在使用具有属性(user_id
、created_at
、...)的 table。我想对自去年 11 月以来每个月创建的 100 到 200 个用户进行抽样。如果我一个月内只 select 100 个用户,那会很容易,因为我可以这样做:
select * from TABLE where created_at >= 'xxxx' and created_at <= 'xxxx'
但我想不出一个干净的方法来为每个月执行此操作,然后将结果放在一起。这有可能以任何方式用 SQL 实现吗?非常感谢。
使用ROW_NUMBER
:
SELECT user_id, created_at -- and other columns
FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY DATE_FORMAT(created_at, '%Y %m')
ORDER BY created_at DESC) rn
FROM yourTable
) t
WHERE t.rn <= 100 AND created_at >= '2017-11-01';
我们使用MySQL函数DATE_FORMAT
创建每个月和年的分区,然后我们只保留每个分区的100个用户。
如果你的日期真的存储为字符串2018-01-01
,那么你可以取字符串的前 7 个字符来获取月份。
然后,使用ROW_NUMBER
按月划分,每个月选取前100名用户。
SELECT
user_id,
created_at
FROM
(
SELECT
user_id,
created_at,
ROW_NUMBER() OVER (PARTITION BY substr(created_at, 1, 7) ORDER BY user_id) AS rn
FROM T
WHERE created_at >= '2017-11-01'
) AS R
WHERE
rn <= 100
;
ORDER BY
定义选择哪些用户。上面的查询根据 ID 选择前 100 位用户,这很可能是按照他们创建的顺序,因此查询基本上选择了每个月创建的前 100 位用户。
如果您想要一些随机选择,则按 returns 随机数的函数排序。这看起来更像是 "sample".
SELECT
user_id,
created_at
FROM
(
SELECT
user_id,
created_at,
ROW_NUMBER() OVER (PARTITION BY substr(created_at, 1, 7) ORDER BY random()) AS rn
FROM T
WHERE created_at >= '2017-11-01'
) AS R
WHERE
rn <= 100
;
假设 t-sql 和 created_at 是日期时间。 您可以使用 ROW_NUMBER() (取决于您可以使用几个不同的 rank/row 类型函数之后的特定行为)为每个 year/month 组合生成一个行号。 https://docs.microsoft.com/en-us/sql/t-sql/functions/row-number-transact-sql?view=sql-server-2017
Declare @rows int = 100,
@date datetime = '2017-11-30'
SELECT *
FROM [YourTable] t
WHERE EXISTS (
SELECT *
from(
Select user_id,
ROW_NUMBER()OVER(PARTITION BY DATEPART(YEAR, created_at), DATEPART(MONTH, created_at) ORDER BY created_at) as rn
FROM [YourTable]
WHERE created_at > @date
) as ds
Where rn <= @rows
and ds.user_id = t.user_id
)
编辑:在指定 rdbms 之前写的,除非不合适,否则我会把它留在这里以防其他人偶然发现。
这里有一篇关于使用 NTILE 和 TABLESAMPLE 的博客,我认为这正是您在这里需要的(分层恒定比例采样)。