Sql server it:只是在一个更大的数据集上进行了测试。它不工作,因为它返回所有行,而不仅仅是顶部5@EdmCoff我刚刚发现,在一个更大的数据集上,上述方法并没有像预期的那样有效。是的,我希望有更多门票的用户有更高的机会被选中。然而,它不应该像拥有最高票数的用户总是首

Sql server it:只是在一个更大的数据集上进行了测试。它不工作,因为它返回所有行,而不仅仅是顶部5@EdmCoff我刚刚发现,在一个更大的数据集上,上述方法并没有像预期的那样有效。是的,我希望有更多门票的用户有更高的机会被选中。然而,它不应该像拥有最高票数的用户总是首,sql-server,distinct,Sql Server,Distinct,it:只是在一个更大的数据集上进行了测试。它不工作,因为它返回所有行,而不仅仅是顶部5@EdmCoff我刚刚发现,在一个更大的数据集上,上述方法并没有像预期的那样有效。是的,我希望有更多门票的用户有更高的机会被选中。然而,它不应该像拥有最高票数的用户总是首先被选中一样。它必须仍然是随机的,就像彩票一样:-)我已经更新了解决方案,你能检查一下吗。如果不起作用,请提供一些示例数据和预期数据。我认为混淆之处在于,此解决方案需要在顶部显示“top 5”,并在主查询中显示另一个“ORDER BY NEWI




it:只是在一个更大的数据集上进行了测试。它不工作,因为它返回所有行,而不仅仅是顶部5@EdmCoff我刚刚发现,在一个更大的数据集上,上述方法并没有像预期的那样有效。是的,我希望有更多门票的用户有更高的机会被选中。然而,它不应该像拥有最高票数的用户总是首先被选中一样。它必须仍然是随机的,就像彩票一样:-)我已经更新了解决方案,你能检查一下吗。如果不起作用,请提供一些示例数据和预期数据。我认为混淆之处在于,此解决方案需要在顶部显示“top 5”,并在主查询中显示另一个“ORDER BY NEWID()”。但这仍然不会使它选择1000张票证的用户的频率高于选择1张票证的用户的频率。我认为这不符合评论中(新增)的要求,即选择1000张票证的用户的概率应高于选择1张票证的用户的概率。编辑:只是在一个更大的数据集上测试它。它不工作,因为它返回所有行,而不仅仅是顶部5@EdmCoff我刚刚发现,在一个更大的数据集上,上述方法并没有像预期的那样有效。是的,我希望有更多门票的用户有更高的机会被选中。然而,它不应该像拥有最高票数的用户总是首先被选中一样。它必须仍然是随机的,就像彩票一样:-)我已经更新了解决方案,你能检查一下吗。如果不起作用,请提供一些示例数据和预期数据。我认为混淆之处在于,此解决方案需要在顶部显示“top 5”,并在主查询中显示另一个“ORDER BY NEWID()”。但是这仍然不会使它选择一个拥有1000张票证的用户的频率比选择一个拥有1张票证的用户的频率更高。嘿,Steve,我刚刚试过运行你的查询,但是在一个拥有100万条记录的测试表中,它总是只返回5张相同的票证。
ROW_NUMBER()OVER(ORDER BY RAND()ASC)作为随机顺序
这行不通。
RAND()
函数在每个查询中执行一次。您需要一个每行执行一次的函数,如
NEWID()
执行。@BaconBits,同意@Klatzen,我已经调整了查询以修复。请注意我对埃德姆科夫回答的评论。@Steve。今天早上刚测试过它,它似乎成功了!嘿,Steve,我刚刚试着运行你的查询,但是在一个有一百万条记录的测试表中,它总是只返回5条相同的票证。
ROW\u NUMBER()OVER(ORDER BY RAND()ASC)AS random\u ORDER
这行不通。
RAND()
函数在每个查询中执行一次。您需要一个每行执行一次的函数,如
NEWID()
执行。@BaconBits,同意@Klatzen,我已经调整了查询以修复。请注意我对埃德姆科夫回答的评论。@Steve。今天早上刚测试过它,它似乎成功了!嘿,大卫。我尝试输入您的查询,但它找不到“如果存在”?可能与我正在运行的SQL server版本有关吗?是的。SQL 2016中引入了DROP TABLE IF EXISTS。如果这是一个存储过程,只需省略DROP表即可。程序结束时会自动删除临时表。啊,好的。只是为了学习,在性能不好的情况下不使用吗?性能始终是“足够好”的问题,这个问题需要某种多通道方法。嘿,大卫。我尝试输入您的查询,但它找不到“如果存在”?可能与我正在运行的SQL server版本有关吗?是的。SQL 2016中引入了DROP TABLE IF EXISTS。如果这是一个存储过程,只需省略DROP表即可。程序结束时会自动删除临时表。啊,好的。只是为了学习,在性能方面使用while不是很糟糕吗?性能始终是“足够好”的问题,这个问题需要某种多通道方法。在100万行和只有4行的表上测试了它,其中只有两行具有唯一的userId。它似乎像我希望的那样工作。非常感谢你!选择这个作为工作答案:-)如果这是为了任何重要的事情,或者如果奖品很重要,我不会依赖
NEWID()
。我将使用
CRYPT\u GEN\u RANDOM(16)
(或其他长度),它从加密API位生成数字。谢谢你的提醒,我一定会调查的。@EdmCoff,谢谢你的提醒!正如我所说,我没有测试我的代码。我对您的方法的唯一观察是,它不会保留多张票子的权重,因为它会在选择赢家之前(按照NEWID()的最终
顺序)(
)消除它们(随机选择受害者票子)。我的代码首先选择中奖彩票的顺序,并且只删除那些在最终输出中代表第二次胜利的彩票(中奖顺序通过在所有彩票仍然存在于集合中的第一轮进行维护)。@steve谢谢。我编辑了这篇文章来警告人们这一点。我想我对简化我的答案有点太着迷了。在100万行和一个只有4行的表上测试了它,其中只有两行有唯一的userId。它似乎像我希望的那样工作。非常感谢你!选择这个作为工作答案:-)如果这是为了任何重要的事情,或者如果奖品很重要,我不会依赖
NEWID()
。我将使用
CRYPT\u GEN\u RANDOM(16)
(或其他长度),它从加密API位生成数字。谢谢你的提醒,我一定会调查的。@EdmCoff,谢谢你的提醒!正如我所说,我没有测试我的代码。我对您的方法的唯一观察是,它不会保留多张票子的权重,因为它会在选择赢家之前(按照NEWID()的最终
顺序)(
)消除它们(随机选择受害者票子)。
ticketId, userId 
SELECT TOP 5 *
FROM Tickets
ORDER BY RAND(CHECKSUM(*) * RAND())
Ticket id:         UserId:
--------------------------
10                 1
25                 1
31                 2
42                 2
56                 3
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
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
 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
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()