从 Snowflake 中的表中选择随机百分比(使用 WHERE 子句时)
Posted
技术标签:
【中文标题】从 Snowflake 中的表中选择随机百分比(使用 WHERE 子句时)【英文标题】:Select random percentage from a table in Snowflake (while using the WHERE clause) 【发布时间】:2021-01-09 01:29:19 【问题描述】:使用此页面作为指南:https://docs.snowflake.com/en/sql-reference/constructs/sample.html
对于本练习,我需要将表中的部分记录拆分为 50/50:
这些工作。我得到了几乎 50% 的表格行数:
SELECT * FROM MyTable SAMPLE (50);
SELECT * FROM MyTable TABLESAMPLE (50);
一旦我应用了 WHERE 子句,SAMPLE 就不再起作用了:
SELECT * FROM MyTable
WHERE country = ‘USA’
AND load_date = CURRENT_DATE
SAMPLE (50);
这让我从上面的雪花页面看到了这个:
方法一;将样本应用于其中一个联接表
select i, j
from table1 as t1 inner join table2 as t2 sample (50)
where t2.j = t1.i
;
方法二;将样本应用于连接表的结果
select *
from (
select *
from t1 join t2
on t1.a = t2.c
) sample (50);
两种方法都有效,但返回的记录数是 57%,而不是两种情况下的 50%。
QUALIFY ROW_NUMBER() OVER (ORDER BY RANDOM())
是更好的选择吗?虽然这确实适用于 WHERE 子句,但我不知道如何设置百分比而不是最大行数。示例:
SELECT * FROM MyTable
WHERE country = ‘USA’
AND load_date = CURRENT_DATE
QUALIFY ROW_NUMBER() OVER (ORDER BY RANDOM()) = (50)
--这给了我 50 行,而不是 50% 的行或 4,457 行(本示例中 where 子句后的总行数为 8,914)
【问题讨论】:
【参考方案1】:在执行 where 子句之前,您需要先对表进行抽样。我相信在您的示例中,首先运行 where 子句,然后对其进行采样。试试这个(未经测试):
with ct as (
SELECT * FROM MyTable SAMPLE (50)
)
select
*
from ct
WHERE country = ‘USA’
AND load_date = CURRENT_DATE
或者我想这个:
select
*
from (SELECT * FROM MyTable SAMPLE (50))
WHERE country = ‘USA’
AND load_date = CURRENT_DATE
【讨论】:
正确,我只需要按百分比拆分表中的某些行。不幸的是,上述方法不起作用,因为随机样本必须是表的子集(USA 和 CURRENT_DATE),而不是相反。【参考方案2】:您可以使用percent_rank()
代替row_number()
:
SELECT * FROM MyTable
WHERE country = 'USA'
AND load_date = CURRENT_DATE
QUALIFY PERCENT_RANK() OVER (ORDER BY RANDOM()) <= 0.5
【讨论】:
不幸的是,这不起作用。随机样本前的计数为 8,914。其中一半是 4,457。当我运行上述程序时,我仍然得到 4,457。知道为什么吗?所有这些变化都给了我 8,914;不是一半:QUALIFY PERCENT_RANK() OVER (ORDER BY RANDOM()) 【参考方案3】:SAMPLE(50)
不是准确返回表中 50% 行的功能。这更像是“生成每行的随机数并评估该数字低于或高于百分比”。所以,它不会产生确定性的结果,而且会因为随机性而产生一定的偏差。
SAMPLE / TABLESAMPLE — 雪花文档: https://docs.snowflake.com/en/sql-reference/constructs/sample.html
BERNOULLI(或 ROW):包括概率为 p/100 的每一行。类似于为每一行翻转一个加权硬币。
如果您想以 50/50 的比例将表拆分为 2 个数据集,NTILE()
会很有帮助。
NTILE(n)
是一个函数,通过为每一行顺序和循环地生成 1 到 n 个数字,将有序数据集平均划分为参数中指定的“桶”数。例如NTILE(2) OVER (ORDER BY C1)
为C1
列排序的每一行依次生成1、2、1、2、...,因此您可以使用“BUCKET”列中的值拆分数据集。
NTILE — 雪花文档: https://docs.snowflake.com/en/sql-reference/functions/ntile.html
将有序数据集平均划分为由 constant_value 指定的桶数。桶按从 1 到 constant_value 的顺序编号。
因此,如果您想从一个表中随机抽取 50% 的行,您可以使用 ORDER BY RANDOM()
和 NTILE()
函数,如下所示:
with ntiled as (
select *, ntile(2) over (order by random()) bucket
from snowflake_sample_data.tpch_sf1.customer
)
select count_if(bucket = 1), count_if(bucket = 2)
from ntiled
;
/*
COUNT_IF(BUCKET = 1) COUNT_IF(BUCKET = 2)
75000 75000
*/
【讨论】:
以上是关于从 Snowflake 中的表中选择随机百分比(使用 WHERE 子句时)的主要内容,如果未能解决你的问题,请参考以下文章
将数据从现有视图加载到 Snowflake 中的表并安排它每天运行 - 增量
如何从 PostgreSQL 中的另一个表中更新具有随机 id 的表