为相等的组拆分数据(PL/SQL、SQL)
Split data for equal group (PL/SQL, SQL)
我有 id 的数量:
Select count(*) Into count_id From table_I;--4
我知道我总共有 total_user = 109
(记录数)。所以我想把它分成相等的组:
Select round(count(*)/count_user,0) Into mapUser From table_U;
所以我有4 group
。在 first three will be 27
和 last should be 28
用户中。
现在我想for each group
分配唯一ID。
set serveroutput on
declare
CURSOR cur IS Select * From table_U FOR UPDATE OF USER_ID;
mapUser NUMBER;
l_rec table_U%rowtype;
x_mapUser Number := 0;--number between 0-27
c_obj_id NUMBER := 1;
count_id NUMBER := 0;
type T1 is table of number(10) index by binary_integer;
V1 T1;
begin
Select count(*) Into count_id From table_I;--count_id = 4
Select round(count(*)/count_id,0) Into mapUser From table_U; --mapUser = 27
SELECT id BULK COLLECT INTO V1 FROM table_I;--it's 4 id (id_1, id_2, id_3, id_4)
OPEN cur;
LOOP FETCH cur INTO l_rec;
EXIT WHEN cur%notfound;
IF x_mapUser > mapUser Then --0-27 > 27
x_mapUser := 1;
c_obj_id := c_obj_id +1;--next value from V1
End if;
UPDATE table_U SET USER_ID = V1(c_obj_id) WHERE CURRENT OF cur;
x_mapUser := x_mapUser +1;
END LOOP;
CLOSE cur;
end;
但我不知道如何更改我的 IF
和 cur
的最后一个值以及分配 id_4
。我在这里做错了:/
我会使用 ntile()
:
select u.*, ntile(4) over (order by user_id) as grp
from table_u u;
我不知道你想要什么顺序,如果有的话。如果您愿意,可以使用随机数。
如果要枚举每个组中的值,请使用子查询:
select u.*, row_number() over (partition by grp order by grp) as seqnum
from (select u.*, ntile(4) over (order by user_id) as grp
from table_u u
) u;
这对我有用:
merge into table_u a
using (select rd, i.id
from (select u.rowid rd, cnt - mod(rownum-1, cnt) rn
from table_u u, (select count(1) cnt from table_i) ) u
join (select row_number() over( order by id) rn, id from table_i) i using (rn)) b
on (a.rowid = b.rd)
when matched then update set a.user_id = b.id
我的测试tables:
create table table_i as (
select level*10 id from dual connect by level <= 4);
create table table_u as (
select cast(null as number(3)) user_id, level id from dual connect by level <= 109);
第二个table的最高值被分配了28次,其他27次。因为我用了
cnt - mod(rownum-1, cnt) rn
计算加入列。我不知道这对你来说是否重要。 :) 此解决方案的基础是 mod()
,它允许我们在 1
和 cnt
之间循环(在本例中为 4)。
您可以在 PLSQL 中执行此操作,如您所展示的,但 SQL 解决方案通常更快,并且在可能的情况下更受青睐。
我发现错误并用我的 PL/SQL 代码做了:
...
x_mapUser Number := 0
...
OPEN cur;
LOOP FETCH cur INTO l_rec;
EXIT WHEN cur%notfound;
UPDATE table_U SET USER_ID = V1(c_obj_id) WHERE CURRENT OF cur;
IF x_mapUser > mapUser-1 AND c_obj_id < count_id Then
x_mapUser := 0;
c_obj_id := c_obj_id +1;
End if;
x_mapUser := x_mapUser +1;
END LOOP;
CLOSE cur;
我有 id 的数量:
Select count(*) Into count_id From table_I;--4
我知道我总共有 total_user = 109
(记录数)。所以我想把它分成相等的组:
Select round(count(*)/count_user,0) Into mapUser From table_U;
所以我有4 group
。在 first three will be 27
和 last should be 28
用户中。
现在我想for each group
分配唯一ID。
set serveroutput on
declare
CURSOR cur IS Select * From table_U FOR UPDATE OF USER_ID;
mapUser NUMBER;
l_rec table_U%rowtype;
x_mapUser Number := 0;--number between 0-27
c_obj_id NUMBER := 1;
count_id NUMBER := 0;
type T1 is table of number(10) index by binary_integer;
V1 T1;
begin
Select count(*) Into count_id From table_I;--count_id = 4
Select round(count(*)/count_id,0) Into mapUser From table_U; --mapUser = 27
SELECT id BULK COLLECT INTO V1 FROM table_I;--it's 4 id (id_1, id_2, id_3, id_4)
OPEN cur;
LOOP FETCH cur INTO l_rec;
EXIT WHEN cur%notfound;
IF x_mapUser > mapUser Then --0-27 > 27
x_mapUser := 1;
c_obj_id := c_obj_id +1;--next value from V1
End if;
UPDATE table_U SET USER_ID = V1(c_obj_id) WHERE CURRENT OF cur;
x_mapUser := x_mapUser +1;
END LOOP;
CLOSE cur;
end;
但我不知道如何更改我的 IF
和 cur
的最后一个值以及分配 id_4
。我在这里做错了:/
我会使用 ntile()
:
select u.*, ntile(4) over (order by user_id) as grp
from table_u u;
我不知道你想要什么顺序,如果有的话。如果您愿意,可以使用随机数。
如果要枚举每个组中的值,请使用子查询:
select u.*, row_number() over (partition by grp order by grp) as seqnum
from (select u.*, ntile(4) over (order by user_id) as grp
from table_u u
) u;
这对我有用:
merge into table_u a
using (select rd, i.id
from (select u.rowid rd, cnt - mod(rownum-1, cnt) rn
from table_u u, (select count(1) cnt from table_i) ) u
join (select row_number() over( order by id) rn, id from table_i) i using (rn)) b
on (a.rowid = b.rd)
when matched then update set a.user_id = b.id
我的测试tables:
create table table_i as (
select level*10 id from dual connect by level <= 4);
create table table_u as (
select cast(null as number(3)) user_id, level id from dual connect by level <= 109);
第二个table的最高值被分配了28次,其他27次。因为我用了
cnt - mod(rownum-1, cnt) rn
计算加入列。我不知道这对你来说是否重要。 :) 此解决方案的基础是 mod()
,它允许我们在 1
和 cnt
之间循环(在本例中为 4)。
您可以在 PLSQL 中执行此操作,如您所展示的,但 SQL 解决方案通常更快,并且在可能的情况下更受青睐。
我发现错误并用我的 PL/SQL 代码做了:
...
x_mapUser Number := 0
...
OPEN cur;
LOOP FETCH cur INTO l_rec;
EXIT WHEN cur%notfound;
UPDATE table_U SET USER_ID = V1(c_obj_id) WHERE CURRENT OF cur;
IF x_mapUser > mapUser-1 AND c_obj_id < count_id Then
x_mapUser := 0;
c_obj_id := c_obj_id +1;
End if;
x_mapUser := x_mapUser +1;
END LOOP;
CLOSE cur;