提问人:Python_Hey 提问时间:9/13/2022 更新时间:9/14/2022 访问量:2484
生成具有条件 Snowflake 的唯一随机数
Generating unique random number with condition Snowflake
问:
我想在 Snowflake 中生成一些具有特定起点/终点的唯一随机数。我希望这些数字从 1,000 开始,到 1,000,000 结束。
另一个要求是在这些数字的开头连接一个字符串。
到目前为止,我一直在使用这个语句:
SELECT CONCAT('TEST-' , uniform(10000, 99000, RANDOM()));
它按预期工作,并给了我例如“TEST-31633”的输出。
但是,问题是我正在为大量行生成这些行,并且我需要它们完全唯一。
我听说过“SEQ1”函数,但不确定如何指定起点以及在开头添加带有 CONCAT 函数的“TEST-”。理想情况下,它们不会严格排列,而是彼此不同。
谢谢
答:
您是否尝试过 UNIFORM,也许这对您有用。https://docs.snowflake.com/en/sql-reference/functions/uniform.html
select CONCAT('TEST-' , uniform(10000, 99000, random())) from table(generator(rowcount => 100));
评论
除非您使用某种计算部分,否则无法保证随机数生成器函数的唯一性。例如:
create or replace table testX as
select CONCAT('TEST-' , to_char(seq4(),'0000'),
uniform(100000, 990000, random())) c
from table(generator(rowcount => 1000));
评论
每当需要在范围内分配唯一的随机数时,最好通过随机排序而不是生成新的随机数来处理。只需生成序列,然后随机排列其顺序即可。
根据用例,您可以简单地生成行,并对所选数量进行限制:order by random()
select * from (
select 'TEST-' || (seq4() + 10000)::string as MY_TEST_ID
from table(generator(rowcount => 89000))
) order by random() limit 10000
;
这个问题的通用解决方案更复杂,但肯定是可能的。JavaScript UDTF 可以使用范围内的所有值填充数组并对其进行随机排序。在 JavaScript UDTF 上使用 window 函数来确保行分布在单个块中,它将允许在任何 SQL 语句的某个范围内创建唯一的随机整数。
首先,创建表函数:
create or replace function UNIQUE_RANDOM_INTEGERS(LBOUND float, UBOUND float)
returns table (UNIQUE_RAND_INT float)
language javascript
strict volatile
as
$$
{
initialize: function (argumentInfo, context) {
this.lBound = argumentInfo.LBOUND.constValue;
this.uBound = argumentInfo.UBOUND.constValue;
this.rSpace = this.uBound - this.lBound + 1;
if (this.lBound >= this.uBound) throw new Error(">>> LBOUND and UBOUND must be constants and UBOUND must be greater than LBOUND <<<");
if (this.rSpace > 25000000) throw new Error (">>> The difference between LBOUND and UBOUND must be 25,000,000 or less.");
this.rands = new Array(this.rSpace);
this.currentRow = 0;
for (let i = 0; i < this.rands.length; i++) {
this.rands[i] = this.lBound + i;
}
this.rands = shuffle(this.rands);
function shuffle(array) {
let currentIndex = array.length, randomIndex;
while (currentIndex != 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
[array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
}
return array;
}
},
processRow: function (row, rowWriter, context) {
//
},
finalize: function (rowWriter, context) {
for (let i = 0; i < this.rSpace; i++) {
rowWriter.writeRow({UNIQUE_RAND_INT:this.rands[i]});
}
},
}
$$;
create or replace function UNIQUE_RANDOM_INTEGERS(LBOUND int, UBOUND int)
returns table(UNIQUE_RAND_INT int)
language sql
as
$$
select UNIQUE_RAND_INT::int from table(UNIQUE_RANDOM_INTEGERS(LBOUND::float, UBOUND::float) over (partition by 1))
$$;
然后,您可以使用以下 SQL 在某个范围内生成唯一的随机数:
select 'TEST-' || UNIQUE_RAND_INT as MY_RAND_VAL
from table(unique_random_integers(10000, 99000));
评论
另一个洗牌答案:
一些设置:
set range_start = 1;
set range_end = 10;
set range_len = $range_end - $range_start;
set name_width = 6;
select
'row_' ||lpad(row_number()over(order by true),$name_width,0) as row_num
from table(generator(ROWCOUNT => $range_len));
给:
ROW_NUM |
---|
row_000001 |
row_000002 |
row_000003 |
row_000004 |
row_000005 |
row_000006 |
row_000007 |
row_000008 |
row_000009 |
所以没有重复,现在洗牌它们,只需给它们和随机值并按顺序排序:
select
'row_' ||lpad(row_number()over(order by true),$name_width,0) as row_num
,random() as rnd_order
from table(generator(ROWCOUNT => $range_len))
order by rnd_order;
ROW_NUM | RND_ORDER |
---|---|
row_000002 | -7,719,769,195,714,581,512 |
row_000007 | -7,227,137,977,152,948,936 |
row_000004 | -4,651,924,808,142,841,706 |
row_000005 | -4,571,360,566,799,746,506 |
row_000003 | -1,059,648,113,216,115,246 |
row_000008 | 1,056,363,703,661,911,623 |
row_000001 | 2,281,704,740,829,606,855 |
row_000006 | 5,648,204,845,936,012,521 |
row_000009 | 8,998,464,501,571,068,967 |
将设置更改为所需的 RELM:
set range_start = 1000;
set range_end = 1000000;
set range_len = $range_end - $range_start;
现在,如果您只想要 500K 答案而不是 9,999K,请在最后限制 500000。.
评论