我有一个名为Tickets
的简单表,其中包含以下列:
ticketId, userId
其中ticketId
是主键,UserId
不是唯一的。
因此,用户可以拥有多张故障单,每张故障单都有唯一的ticketId
。
我很难找到解决问题的方法,即我需要通过5个唯一的userId选择5张随机票。
我知道如何使用以下查询选择随机故障单:
SELECT TOP 5 *
FROM Tickets
ORDER BY RAND(CHECKSUM(*) * RAND())
返回类似的内容:
Ticket id: UserId:
--------------------------
10 1
25 1
31 2
42 2
56 3
我的问题是:我需要在查询中添加什么来选择不同userId之间的随机行,以便它不会为用户返回多个唯一的票证
介意我需要性能最正确的解决方案,因为从长远来看,这个表可能会被数百万行填充。
提前致谢, 基督教
修改 用户拥有的门票越多,选择的机会就越大。但是它应该仍然是随机选择的,而不仅仅是选择具有最高票数的用户。就像在抽奖中一样。
换句话说,它应该在所有行之间选择5个随机行,但要确保5行具有唯一的userId。
答案 0 :(得分:2)
请尝试这样.... NEWID()
Select UserId
from
(
SELECT TOP 5 UserId
FROM Tickets
ORDER BY NEWID()
)k
CROSS APPLY
(
select top 1 TicketId
from Tickets T WHERE T.UserId = k.UserId
ORDER BY NEWID()
)u
答案 1 :(得分:2)
编辑正如评论中指出的那样,此解决方案无法按票数对用户进行适当加权(因此,具有1000张票证的用户错误地与具有1张票证的用户具有相同的获胜更改)。这对我来说尤其愚蠢,因为我在其他答案中指出了这个问题。
鉴于史蒂夫现在有他的解决方案,我认为这是更好的答案。
原始回答:
我认为类似以下内容的作品:
SELECT top 5 ticketid, userid
FROM
(
SELECT ticketid, userid, ROW_NUMBER() OVER (PARTITION BY userid ORDER BY NEWID()) as nid
FROM tickets
) a
WHERE nid = 1
ORDER BY NEWID()
这是一个sql fiddle来玩它。
信用到期的信用:我基于Steve的解决方案,我认为这种解决方案不正确。
答案 2 :(得分:1)
我认为如下。
请注意此代码未经测试,因此请原谅任何小的语法错误。
WITH randomised_tickets AS
(
SELECT
*
,ROW_NUMBER() OVER (ORDER BY NEWID() ASC) AS random_order
FROM Tickets
)
,ordered_winning_tickets AS
(
SELECT
*
,ROW_NUMBER() OVER (PARTITION BY userId ORDER BY random_order ASC) AS user_win_order
FROM randomised_tickets
)
SELECT TOP 5
*
FROM
ordered_winning_tickets
WHERE
user_win_order = 1 --eliminate 2nd wins from the list
ORDER BY
random_order
答案 3 :(得分:0)
您可以尝试这样的方法,在临时表上使用ignore_dup_key来消除用户的重复:
drop table if exists #WinningTickets
create table #WinningTickets(PickId int identity primary key, TicketId int, UserId int)
create unique index ix_unique_user on #WinningTickets(UserId) with (ignore_dup_key=on)
while ( select count(*) from #WinningTickets ) < 5
begin
insert into #WinningTickets
select top 10 TicketId, UserId
from Tickets
order by newid()
end
select top 5 *
from #WinningTickets
order by PickId