PostgreSQL分配随机、非重复的值
我有一张学生表,如下所示:PostgreSQL分配随机、非重复的值,sql,postgresql,join,count,window-functions,Sql,Postgresql,Join,Count,Window Functions,我有一张学生表,如下所示: firstname | id ----------------+---- Student1 | 1 Student2 | 2 Student3 | 3 Student4 | 4 Student5 | 5 Student6 | 6 Student7 | 7 Student8 | 8 Student9 | 9 t
firstname | id
----------------+----
Student1 | 1
Student2 | 2
Student3 | 3
Student4 | 4
Student5 | 5
Student6 | 6
Student7 | 7
Student8 | 8
Student9 | 9
topic | n_tasks
---------+----
1 | 11
2 | 3
3 | 6
4 | 9
5 | 12
6 | 13
7 | 10
8 | 25
9 | 10
10 | 10
11 | 22
12 | 20
14 | 18
15 | 18
16 | 7
table topic1
firstname | task
----------------+----
Student1 | 1
Student8 | 2
Student4 | 3
Student3 | 4
Student7 | 5
Student9 | 6
Student6 | 7
Student7 | 8
Student8 | 9
Student1 | 10
Student2 | 11
table topic2
firstname | task
----------------+----
Student1 | 1
Student2 | 2
Student3 | 3
Student4 | 1
Student5 | 3
Student6 | 2
Student7 | 2
Student8 | 3
Student9 | 1
以及包含每个主题要执行的任务数的表,如下所示:
firstname | id
----------------+----
Student1 | 1
Student2 | 2
Student3 | 3
Student4 | 4
Student5 | 5
Student6 | 6
Student7 | 7
Student8 | 8
Student9 | 9
topic | n_tasks
---------+----
1 | 11
2 | 3
3 | 6
4 | 9
5 | 12
6 | 13
7 | 10
8 | 25
9 | 10
10 | 10
11 | 22
12 | 20
14 | 18
15 | 18
16 | 7
table topic1
firstname | task
----------------+----
Student1 | 1
Student8 | 2
Student4 | 3
Student3 | 4
Student7 | 5
Student9 | 6
Student6 | 7
Student7 | 8
Student8 | 9
Student1 | 10
Student2 | 11
table topic2
firstname | task
----------------+----
Student1 | 1
Student2 | 2
Student3 | 3
Student4 | 1
Student5 | 3
Student6 | 2
Student7 | 2
Student8 | 3
Student9 | 1
我想根据以下规则随机分配任务给学生:
- 当任务数量与学生完全相同时,每个 学生应随机分配一个任务编号
- 当任务多于学生时,学生名单应 重复一遍
- 当任务少于学生时,任务列表应 重复一遍
- 如果学生或任务需要重复,则应随机选择
firstname | id
----------------+----
Student1 | 1
Student2 | 2
Student3 | 3
Student4 | 4
Student5 | 5
Student6 | 6
Student7 | 7
Student8 | 8
Student9 | 9
topic | n_tasks
---------+----
1 | 11
2 | 3
3 | 6
4 | 9
5 | 12
6 | 13
7 | 10
8 | 25
9 | 10
10 | 10
11 | 22
12 | 20
14 | 18
15 | 18
16 | 7
table topic1
firstname | task
----------------+----
Student1 | 1
Student8 | 2
Student4 | 3
Student3 | 4
Student7 | 5
Student9 | 6
Student6 | 7
Student7 | 8
Student8 | 9
Student1 | 10
Student2 | 11
table topic2
firstname | task
----------------+----
Student1 | 1
Student2 | 2
Student3 | 3
Student4 | 1
Student5 | 3
Student6 | 2
Student7 | 2
Student8 | 3
Student9 | 1
在需要重复任务或学生的情况下,理想情况下,在所有其他学生或任务完成之前,学生或任务都不会重复
经过深思熟虑,我认为这个问题可能不适合PostgreSQL,最好用另一种编程语言来解决,但谢谢你的建议 您可以根据需要尝试此功能:
create or replace function fun(topic_id int) returns bool as
$$
declare
st_count int;
topic_count int;
begin
select count(*) into st_count from student;
select n_tasks into topic_count from topic where topicid=topic_id;
if st_count=topic_count and st_count>0 and topic_count>0 then
execute format('create table %I (first_name varchar, task int)','topic'||topic_id);
execute format('insert into %I select name,row_number() over (order by random()) rn from student','topic'||topic_id);
return true;
end if;
if st_count>topic_count and st_count>0 and topic_count>0 then
execute format('create table %I (first_name varchar, task int)','topic'||topic_id);
execute format('insert into %I
with cte as (select generate_series(1,%s) rn),
cte1 as (
select row_number() over (order by random()) rn,
name from student t1) select t1.name, coalesce(t2.rn,round(random()* %s))
from cte1 t1 left join cte t2 on t1.rn=t2.rn',
'topic'||topic_id,topic_count,topic_count);
return true;
end if;
if st_count<topic_count and st_count>0 and topic_count>0 then
execute format('create table %I (first_name varchar, task int)','topic'||topic_id);
execute format('insert into %I with cte as (select generate_series(1,%s) rn),
cte1 as (select row_number() over (order by random()) rn, name from student t1),
cte2 as (select coalesce(t2.rn, round(random()* %s)) rn_,t1.rn from cte t1
left join cte1 t2 on t1.rn=t2.rn)
select t1.name,t2.rn from cte2 t2 inner join cte1 t1 on t1.rn=t2.rn_',
'topic'||topic_id,topic_count,st_count);
return true;
end if;
return false;
end;
$$
language plpgsql
这将生成具有给定条件的所有表
这是一个有趣的问题 首先,可以使用
generate_series()
创建任务行。然后,你可以随机列举学生
最后,您可以在连接条件中使用算术来考虑每一端的“缺失”行:其思想是将任务数量与学生数量进行比较,然后使用模来偏移最大组的值,并适当地分布其他不匹配的行
select s.firstname, t.task
from (
select
s.*,
row_number() over(order by random()) rn,
count(*) over() cnt
from students s
) s
inner join (
select t.*, x.task
from topic t
cross join lateral generate_series(1, n_tasks) as x(task)
) t
on (s.cnt <= t.n_tasks and s.rn = t.task % s.cnt + 1)
or (t.n_tasks < s.cnt and t.task = s.rn % t.n_tasks + 1)
where t.topic = 1
order by t.topic, t.task
专题2:
firstname | task
:-------- | ---:
Student9 | 1
Student3 | 1
Student7 | 1
Student1 | 2
Student6 | 2
Student8 | 2
Student4 | 3
Student2 | 3
Student5 | 3
名字|任务
:-------- | ---:
学生9 | 1
学生3 | 1
学生7 | 1
学生1 | 2
学生6 | 2
学生8 | 2
学生4 | 3
学生2 | 3
学生5 | 3
不,上述场景并不不适合PostgreSQL。尝试下面的解决方案。