我已经搜遍了所有的答案,尽管人们说不使用ORDER BY RAND()条款,但我认为对于我的目的来说这是好的,因为这是一场几乎没有超过几百条记录的比赛PER时间比赛。
所以基本上我需要从竞赛条目表中检索5个随机记录。但是,任何忠诚度客户都会收到额外的EXTRA条目,例如:
compEntryid | firstName | lastName | compID |
1 | bob | smith | 100
2 | bob | smith | 100
3 | jane | doe | 100
4 | sam | citizen | 100
等
因此,我们为忠诚会员提供了获奖的更好机会。但是我有点担心通常的ORDER BY RAND()返回的结果可能包括同一个人的2个条目?什么是优化方法,以确保我们真正拥有5个随机记录,但同时为这些额外的进入者提供更好或(加权)的机会?很高兴使用多个查询,子查询甚至是MySQL和PHP的混合?非常感谢任何建议,谢谢!
低音
编辑:
这两个查询都有效!
QUERY1
SELECT concat(firstName, " ", lastName) name,id, email
FROM t WHERE
RAND()<(SELECT ((5/COUNT(id))*10) FROM t)
group by email ORDER BY RAND() limit 5;
QUERY2
select distinct
email, id, firstName, lastName from
(
select id ,
email, firstName , lastName , compID, rand()/(select count(*) from t where
email=t1.email
) as rank
from t t1
where compID = 100
order by rank) t2 limit 5;
答案 0 :(得分:1)
如果你有几百条记录,我认为rand()解决方案的顺序应该没问题: 子查询将命令加权条目数,但重复项仍然存在。父SELECT将采用前5个不同的行。
SELECT DISTINCT firstName ,
lastName ,
compID
FROM
( SELECT compEntryid ,firstName , lastName , compID, rand()/(select count(*)
FROM t
WHERE firstName=t1.firstName AND
lastName = t1.lastName) AS rank
FROM t t1
WHERE compID = 100
ORDER BY rank) t2
LIMIT 5
答案 1 :(得分:0)
如果你想返回一个compEntryid,我想你需要使用一个子查询。
SELECT t.firstName, t.lastName, t.compID, MIN(compEntryid)
FROM t
INNER JOIN
(
SELECT DISTINCT firstName, lastName, compID
FROM t
ORDER by rand()
LIMIT 5
) t2
ON t.firstName = t2.firstName
AND t.lastName = t2.lastName
AND t.compID = t2.compID
GROUP BY t.firstName, t.lastName, t.compID;
这使用子查询获得5个随机firstName / lastName / compID。然后连接到表以获得MIN compEntryId。
但是对此不确定。认为它会在执行订单/限制之前消除子查询中的重复项,这会阻止有更多条目的人有更多机会。
修改
更多的游戏,我想我找到了解决方案。虽然效率不是其优点之一。
SELECT MIN(compEntryid), firstName, lastName, compID
FROM
(
SELECT firstName, lastName, compID, compEntryid, @seq:=@seq+1 AS seq
FROM
(
SELECT firstName, lastName, compID, compEntryid
FROM t
ORDER by rand()
) sub0
CROSS JOIN (SELECT @seq:=0) sub1
) sub2
GROUP BY sub2.firstName, sub2.lastName, sub2.compID
ORDER BY MIN(seq)
LIMIT 5
这有一个内部子查询,以随机顺序获取所有记录。在另一个子查询周围添加序列号到记录。外部查询按名称等分组,并按该名称的最小序列号排序。 compEntryId只是作为名称/竞赛的MIN获取(我假设你不太关心这个)。
这样,如果有人有5个条目,则内部子查询会将它们混合在列表中。下一个子查询将添加序列号。在这个阶段,这5个条目可以是序列号1到5.外部序列号将按名称的最低序列号排序,而忽略其他序列号,因此在这5个序列中只使用序列号1,忽略2到5个,下一个选定的人是序列号为6的人。
这样他们拥有的参赛作品越多,他们就越有可能成为胜利者,但不能成为5名获胜者中的2名。
感谢kiks73设置了一些sqlfiddle数据: -
http://sqlfiddle.com/#!2/cd777/1
修改
@ kiks73基于上述解决方案。调整以使用非相关子查询计数,并消除一些不确定性。例如,在他的解决方案中,我不太确定MySQL是否会通过隐式执行GROUP BY来选择执行DISTINCT,这也会在执行限制之前隐式地执行结果的撤销(它似乎不是,但是我我不确定是否已定义此行为。
SELECT t.firstName ,
t.lastName ,
t.compID,
MIN(rand() / t1.entry_count) AS rank
FROM
(
SELECT firstName, lastName, compID, COUNT(*) AS entry_count
FROM t
GROUP BY firstName, lastName, compID
) t1
INNER JOIN t
ON t.firstName=t1.firstName
AND t.lastName = t1.lastName
AND t.compID = t1.compID
GROUP BY t.firstName, t.lastName, t.compID
ORDER BY rank
LIMIT 5