使用此页面作为指南: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);
这让我从上面的雪花页面找到了这个:
方法1;将样本应用于其中一个连接表
select i, j
from table1 as t1 inner join table2 as t2 sample (50)
where t2.j = t1.i
;
方法2;将样本应用于连接表的结果
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)
在执行 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
percent_rank()
代替 row_number()
:
SELECT * FROM MyTable
WHERE country = 'USA'
AND load_date = CURRENT_DATE
QUALIFY PERCENT_RANK() OVER (ORDER BY RANDOM()) <= 0.5
SAMPLE(50)
不是一个返回表中 50% 行的功能。这更像是“生成每行的随机数并评估该数字低于或高于百分比”。所以,它不会产生确定性的结果,并且会因为随机性而存在一些偏差。
示例/表格示例 — Snowflake 文档: 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
*/