SQL Server:从表中选择具有不同id的随机行,其中id不是

时间:2018-01-03 15:43:20

标签: sql-server distinct

我有一个名为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。

4 个答案:

答案 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