这是我所拥有的基本设置的模拟:每个人可以拥有多个财产 人员表:
id name
1 Carl
2 Sam
3 Tom
4 Jack
财产表:
possession personId
car 2
shoes 2
shovel 2
tent 3
matches 3
axe 4
我想生成一组随机的属于一组人的财产,每人一次拥有。
因此,在非SQL世界中,我会生成一组N个随机人员,然后为该组中的每个人选择一个随机拥有。但是我如何在SQL语义中实现它?
我想过随机抽取一些物品:
SELECT * FROM Posessions WHERE 0.01 >= RAND()
然后过滤掉重复的人,但这并不好,因为它最终有利于拥有大量财产的人,我希望每个人都有平等的机会被选中。
有解决这个问题的规范方法吗?
P.S。 Person包含~50000个实体,Possession包含~2500000个实体,但我只需要执行一次这样的采样,因此它可能有点慢。
答案 0 :(得分:0)
为什么不随机抽取一组人并加入随机排名的分数。像下面的东西。很抱歉,如果它包含任何拼写错误,但我现在没有DB检查它:
select * from (
(select top 1 percent * from persons order by newid()) a
inner join
(select p.*, ROW_NUMBER() OVER (partition by personId order by newid()) r from posessions p) b
on (a.personId = b.personId)
)
where r = 1;
答案 1 :(得分:0)
一种方式是(每人2人,每人1人)
DECLARE @PeopleCount INT = 2,
@PossessionsPerPersonCount INT = 1;
SELECT *
FROM (SELECT TOP (@PeopleCount) *
FROM Persons
ORDER BY CRYPT_GEN_RANDOM(4)) RandomPersons
OUTER APPLY (SELECT TOP (@PossessionsPerPersonCount) * FROM Posessions p
WHERE RandomPersons.id = p.personId
ORDER BY CRYPT_GEN_RANDOM(4)) RandomPosessions
希望Possession在personId上有一个索引,以便它可以搜索每个人的相关行数(平均50),而不是扫描每个人的表格中的所有2,500,000。
我上面使用了OUTER APPLY
,因为并非你示例数据中的所有人都拥有财产(即Carl没有)。
如果您只想包含拥有财产且想要每人拥有一个人的财产,那么您可以使用此权限。
DECLARE @PeopleCount INT = 2;
SELECT TOP (@PeopleCount) *
FROM Persons
CROSS APPLY (SELECT TOP (1) * FROM Posessions p
WHERE Persons.id = p.personId
ORDER BY CRYPT_GEN_RANDOM(4)) RandomPosessions
ORDER BY CRYPT_GEN_RANDOM(4);
答案 2 :(得分:0)
以下查询将为您生成3个随机样本
SELECT p.id,
(SELECT posession FROM posessions p1 where p1.id=p.id ORDER BY RAND() LIMIT 1) as posession
FROM posessions p
GROUP BY p.id
ORDER BY RAND()
LIMIT 3
子查询生成每个人的随机位置,而外部查询生成随机人。