我有一个带有 userId 和用户名的表。我想根据百分比为每一行分配随机数。例如:我想为每一行分配 6、7、8。但是 50% 的记录应该分配 6 个。45% 的行应分配 7 个,其余 5% 的行应分配 8 个。
有没有办法在 SQL 中做到这一点?
输出应该是用户 ID、用户名、随机数。
如果 PL/SQL 是一个选项:
DECLARE
RAND number := dbms_random.value;
BEGIN
IF RAND <= 0.50 THEN
RAND := 6;
ELSIF RAND <= 0.95 THEN
RAND := 7;
ELSE
RAND := 8;
END IF;
dbms_output.put_line(RAND); -- this line can be changed by the 'insert'
END;
select userid, username, case cast (dbms_random.value(0, 20) as int)
when 0 then 6
when 1 then 6
when 2 then 6
when 3 then 6
when 4 then 6
when 5 then 6
when 6 then 6
when 7 then 6
when 8 then 6
when 9 then 6
when 10 then 7
when 11 then 7
when 12 then 7
when 13 then 7
when 14 then 7
when 15 then 7
when 16 then 7
when 17 then 7
when 18 then 7
when 19 then 8
else -1 -- should never happen
end as "RANDOM"
from mytable;
因为这些值是随机生成的,所以这不会准确地给你 50/45/5 的比率,但如果你有大量的行应该接近它(并且随机数函数很好)
另一种方法是对order by random
行分配 6 到前 50%,7 到下一个 45%,8 到其余部分。这将确保您拥有正确的比率:
with myset as (
select userid, username
from my_user_table
order by dbms_random.value(0,1)
)
select * from
(
select
userid,
username,
case when rownum <= (select count(*) from myset) * 0.50 then 6
when rownum <= (select count(*) from myset) * 0.95 then 7
else 8
end as random
from myset) t
order by t.userid;
我发现分配随机数的最佳方法是通过伪随机数生成器:
对于您的情况:
SELECT t.*,
( CASE
WHEN Mod(rownum * 71 + 107, 257) < .5 * 257 THEN 6
WHEN Mod(rownum * 63 + 107, 257) BETWEEN 0.5 * 257 AND 0.95 * 257
THEN 7
ELSE 8
END ) AS val
FROM (SELECT t.*,
Row_number()
OVER (
partition BY NULL) AS rownum
FROM t) t
这个想法是,乘以一个素数,加上另一个素数,然后通过三分之一取余数是随机数的一个很好的近似值。不完美,但对于大多数用途来说已经足够了。
此外,这里的百分比是近似值。