随机顺序设置为特定日期

时间:2021-03-22 00:36:17

标签: sql sql-server random sql-order-by

有没有办法对事件列表进行随机排序并让它只在当天保持这种状态?涉及分页,因此缓存并不是一个好的选择。

我知道我可以按 NEWID() 进行随机排序,但是如果它从未被缓存并且在第 1 页上包含相同的项目,则会在第 100 页上显示不同的顺序。如果是按日期,那么它会显示排序,无论页面缓存如何,并在第二天重置。

    WITH PagedResults AS 
        (
            SELECT CASE WHEN @SortOrder = 'Name' AND @SortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY ep.Name DESC, ev.Id ASC)
            ELSE ROW_NUMBER() OVER (ORDER BY ev.Id ASC) END  AS [Row],
            CASE WHEN @SortOrder = 'Name' AND @SortDirection = 'DESC' THEN ROW_NUMBER() OVER (ORDER BY ep.Name ASC, ev.Id DESC)
            ELSE ROW_NUMBER() OVER (ORDER BY ev.Id DESC)
            END  AS [RowReverse],
                ev.Id,
                ep.Name,
    )
        SELECT 
                [Row] + RowReverse - 1 AS Total, 
                [Row],
                [RowReverse],
                Id, 
                Name,
        FROM PagedResults
        WHERE [Row] BETWEEN (((@Page - 1) * @PageSize) + 1) AND (@Page * @PageSize)
        ORDER BY [Row], [RowReverse] DESC

1 个答案:

答案 0 :(得分:4)

在下面我将使用表 sortme 定义为:

CREATE TABLE sortme
             (id integer
                 IDENTITY (1, 1),
              PRIMARY KEY(id));

ORDER BY rand(<seed>) 与源自当天的 <seed> 一起使用可能是想到的第一种方法。

DECLARE @today datetime = '2021-01-01 01:01:01';

SELECT *
       FROM sortme
       ORDER BY rand(convert(integer,
                             convert(varchar(8),
                                     @today,
                                     112)));

rand() 保证生成的值相同,如果 <seed> 相同。所以我们检查了这一点。有点......因为每一行的值也将相同。因此,将 rand(<seed>) 用于固定的 <seed> 将有效地什么都不做。

db<>fiddle

我们可以尝试通过将随机值绑定到结果的键来克服这个问题。随机值对于 day 和 key,即 key 标识的行,将在一天内保持稳定。

    DECLARE @today datetime = '2021-01-01 01:01:01';
    SELECT *
           FROM sortme
           ORDER BY rand(id * 100000000
                         + 
                         convert(integer,
                                 convert(varchar(8),
                                         @today,
                                         112)));

但不幸的是,将密钥和我想出的日期相结合的每个(简单)公式确实会产生足够接近每一天的随机值,因此每天的顺序都相同。它没有很好地分散。

db<>fiddle

现在,如果我们考虑一下,我们想要一个可以很好地分散甚至单调增加的值的函数。这就是哈希函数的领域。

所以我们可以使用 hashbytes()

DECLARE @today datetime = '2021-01-01 01:01:01';

SELECT *
       FROM sortme
       ORDER BY hashbytes('SHA2_512',
                          concat(convert(varchar(8),
                                         @today,
                                         112),
                                 id));

散列将全天保持稳定,行的键仅取决于这些值。并且(某些)散列函数散布良好的事实使结果“看起来随机”。

db<>fiddle

从表中删除或插入当然会导致行出现或消失在其他“旧”行或剩余行之间。但是,如果我们使用的键是稳定的,比如不填充间隙的自动增量,那么“旧”或剩余行之间的顺序无论如何都会在一天中保持稳定。

当然,请注意,就不可预测而言,这不是随机的!

但我认为它的目的只是为了改善用户体验,每天呈现一个“感觉”随机的结果,使内容更加有趣和令人兴奋。应该足够了。

相关问题