有没有办法仅使用 SQL 将 table 中的行洗牌成独特的固定大小块?
Is there a way to shuffle rows in a table into distinctive fixed size chunks using SQL only?
我有一个非常大的 table(约 3 亿行),其结构如下:
my_table(id, group, chunk, new_id),其中chunk和new_id设置为NULL。
我想将每个组的行设置为一个随机块,块中有不同的 new_id。每个块的大小应固定为 100。
例如,如果组 A 有 1278 行,则它们应分为 13 个块 (0-12),12 个块,100 行 s.t。 new_id 在范围 (0-99) 内,另一个包含 78 行的块 s.t。 new_id 在范围 (0-77) 内。
块中和块内的组织应该是随机排列,其中 A 中的每一行都分配有唯一的(块,new_id)元组。
我使用 pandas 成功地做到了,但它需要几个小时,主要是由于内存和带宽限制。
是否可以仅使用 SQL 查询来执行?
我正在使用 postgres 9.6。
你可以用 row_number()
:
select id, group, rn / 100 chunk, rn % 100 new_id
from (select t.*, row_number() over(order by random()) - 1 rn from mytable t) t
内部查询为每条记录分配一个随机整数(从 0 开始)。外部查询通过算术计算块和新 ID。
如果您想要 update
查询:
update mytable t set chunk = x.rn / 3, new_id = x.rn % 3
from (select id, row_number() over(order by random()) - 1 rn from mytable t) x
where x.id = t.id
Demo on DB Fiddle 对于包含 3 条记录的 20 条记录的数据集。
之前:
id | grp | chunk | new_id
-: | --: | ----: | -----:
1 | 1 | nullnull
2 | 2 | nullnull
3 | 3 | nullnull
4 | 4 | nullnull
5 | 5 | nullnull
6 | 6 | nullnull
7 | 7 | nullnull
8 | 8 | nullnull
9 | 9 | nullnull
10 | 10 | nullnull
11 | 11 | nullnull
12 | 12 | nullnull
13 | 13 | nullnull
14 | 14 | nullnull
15 | 15 | nullnull
16 | 16 | nullnull
17 | 17 | nullnull
18 | 18 | nullnull
19 | 19 | nullnull
20 | 20 | nullnull
之后:
id | grp | chunk | new_id
-: | --: | ----: | -----:
19 | 19 | 0 | 0
11 | 11 | 0 | 1
20 | 20 | 0 | 2
12 | 12 | 1 | 0
14 | 14 | 1 | 1
17 | 17 | 1 | 2
3 | 3 | 2 | 0
8 | 8 | 2 | 1
5 | 5 | 2 | 2
13 | 13 | 3 | 0
10 | 10 | 3 | 1
2 | 2 | 3 | 2
16 | 16 | 4 | 0
18 | 18 | 4 | 1
6 | 6 | 4 | 2
1 | 1 | 5 | 0
15 | 15 | 5 | 1
7 | 7 | 5 | 2
4 | 4 | 6 | 0
9 | 9 | 6 | 1
我有一个非常大的 table(约 3 亿行),其结构如下: my_table(id, group, chunk, new_id),其中chunk和new_id设置为NULL。
我想将每个组的行设置为一个随机块,块中有不同的 new_id。每个块的大小应固定为 100。
例如,如果组 A 有 1278 行,则它们应分为 13 个块 (0-12),12 个块,100 行 s.t。 new_id 在范围 (0-99) 内,另一个包含 78 行的块 s.t。 new_id 在范围 (0-77) 内。
块中和块内的组织应该是随机排列,其中 A 中的每一行都分配有唯一的(块,new_id)元组。
我使用 pandas 成功地做到了,但它需要几个小时,主要是由于内存和带宽限制。
是否可以仅使用 SQL 查询来执行? 我正在使用 postgres 9.6。
你可以用 row_number()
:
select id, group, rn / 100 chunk, rn % 100 new_id
from (select t.*, row_number() over(order by random()) - 1 rn from mytable t) t
内部查询为每条记录分配一个随机整数(从 0 开始)。外部查询通过算术计算块和新 ID。
如果您想要 update
查询:
update mytable t set chunk = x.rn / 3, new_id = x.rn % 3
from (select id, row_number() over(order by random()) - 1 rn from mytable t) x
where x.id = t.id
Demo on DB Fiddle 对于包含 3 条记录的 20 条记录的数据集。
之前:
id | grp | chunk | new_id -: | --: | ----: | -----: 1 | 1 | nullnull 2 | 2 | nullnull 3 | 3 | nullnull 4 | 4 | nullnull 5 | 5 | nullnull 6 | 6 | nullnull 7 | 7 | nullnull 8 | 8 | nullnull 9 | 9 | nullnull 10 | 10 | nullnull 11 | 11 | nullnull 12 | 12 | nullnull 13 | 13 | nullnull 14 | 14 | nullnull 15 | 15 | nullnull 16 | 16 | nullnull 17 | 17 | nullnull 18 | 18 | nullnull 19 | 19 | nullnull 20 | 20 | nullnull
之后:
id | grp | chunk | new_id -: | --: | ----: | -----: 19 | 19 | 0 | 0 11 | 11 | 0 | 1 20 | 20 | 0 | 2 12 | 12 | 1 | 0 14 | 14 | 1 | 1 17 | 17 | 1 | 2 3 | 3 | 2 | 0 8 | 8 | 2 | 1 5 | 5 | 2 | 2 13 | 13 | 3 | 0 10 | 10 | 3 | 1 2 | 2 | 3 | 2 16 | 16 | 4 | 0 18 | 18 | 4 | 1 6 | 6 | 4 | 2 1 | 1 | 5 | 0 15 | 15 | 5 | 1 7 | 7 | 5 | 2 4 | 4 | 6 | 0 9 | 9 | 6 | 1