我有两张这样的表:
CREATE TABLE people (
id INT NOT NULL,
PRIMARY KEY (id)
)
CREATE TABLE pairs (
person_a_id INT,
person_b_id INT,
FOREIGN KEY (person_a_id) REFERENCES people(id),
FOREIGN KEY (person_b_id) REFERENCES people(id)
)
我想从人员表中随机选择一对人,在选择它们之后,我将随机选择对添加到配对表中。 person_a_id始终指的是该对id较低的人(因为该对的顺序不相关)。
问题是我从不想两次选择同一对,所以在返回随机选择的对之前我需要检查对表。
是否可以以合理有效和优雅的方式使用单个SQL查询来执行此操作?
(我正在使用Java Persistence API执行此操作,但希望我能够将任何答案翻译成JPA代码)
答案 0 :(得分:4)
select a.id, b.id
from people1 a
inner join people1 b on a.id < b.id
where not exists (
select *
from pairs1 c
where c.person_a_id = a.id
and c.person_b_id = b.id)
order by a.id * rand()
limit 1;
如果你一次“抽签”, Limit 1
只返回一对。否则,将你需要的数量增加到极限。
以上查询假定您可以
1 - 2
2 - 7
并且配对2 - 7
有效,因为它不存在,即使2再次出现。如果你只希望一个人在only one
对中出现,那么
select a.id, b.id
from people1 a
inner join people1 b on a.id < b.id
where not exists (
select *
from pairs1 c
where c.person_a_id in (a.id, b.id))
and not exists (
select *
from pairs1 c
where c.person_b_id in (a.id, b.id))
order by a.id * rand()
limit 1;
如果要在一个查询中生成multiple pairs
, AND 目标表仍为空,则可以使用此单个查询。请注意LIMIT 6
仅返回3对。
select min(a) a, min(b) b
from
(
select
case when mod(@p,2) = 1 then id end a,
case when mod(@p,2) = 0 then id end b,
@p:=@p+1 grp
from (
select id
from (select @p:=1) p, people1
order by rand()
limit 6
) x
) y
group by floor(grp/2)
答案 1 :(得分:1)
这不能在基于单查询集的方法中完成,因为您的集合不知道在对表中插入了哪些对。
相反,你应该循环
WHILE EXISTS(SELECT * FROM people
WHERE id NOT IN (SELECT person_a_id FROM pairs)
AND id NOT IN (SELECT person_b_id FROM pairs)
当有无与伦比的人时,这将循环。
那么你应该从1到该表的CNT(*)
两个随机数
它为您提供了无与伦比的人数...如果您获得两次相同的数字,请再次滚动。 (如果你担心这个问题,可以从集合的两半中随机化数字......但是你会根据你的排序标准丢失一些随机性)
配对那些人。
洗涤,冲洗,重复...... 你唯一的“重做”将是你生成相同的随机数两次...更有可能因为你得到的人很少,但最多只有25%的几率(远远超过1 / n ^ 2)