userIdとusernameのテーブルがあります。パーセントに基づいて各行に乱数を割り当てたいと思います。例:各行に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 の比率が正確に得られるわけではありませんが、多数の行がある場合 (および乱数関数が適切である場合) はそれに近いはずです。
もう 1 つの方法はorder by random
、行に対して、最初の 50% に 6 を割り当て、次の 45% に 7 を割り当て、残りに 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
1 つの素数を掛けて別の素数を足し、残りを 3 分の 1 でとることは、乱数のかなり良い近似であるという考え方です。完璧ではありませんが、ほとんどの目的には十分です。
また、ここでのパーセンテージは概算です。