【问题标题】:CRYPT_GEN_RANDOM strange effectsCRYPT_GEN_RANDOM 奇怪的效果
【发布时间】:2011-04-15 14:43:06
【问题描述】:

我想从一小部分整数(小于 200)中随机选择一个值。作为

的替代品
SELECT RAND()

我正在尝试使用

CAST(CAST(CRYPT_GEN_RANDOM(2) AS INTEGER) AS FLOAT) / 65535

但我得到了一些奇怪的效果。

例如:

WITH Numbers (num)
     AS
     (
      SELECT num
        FROM (
              VALUES (1), (2), (3), (4), 
                     (5), (6), (7), (8), 
                     (9), (10)
             ) AS Numbers (num)
     ), 
     RandomNumber (num)
     AS 
     (
      SELECT CAST(
                  (CAST(CAST(CRYPT_GEN_RANDOM(2) AS INTEGER) AS FLOAT) / 65535) 
                     * (SELECT COUNT(*) FROM Numbers) + 1 
                  AS INTEGER
                 )
     )
SELECT T1.num, R1.num
  FROM Numbers AS T1 
       INNER JOIN RandomNumber AS R1
          ON T1.num = R1.num;

我希望这能准确返回一行,两列值相等。

但是,它返回零、一行或多行,列值只是偶尔相等。

知道这里发生了什么吗?

【问题讨论】:

标签: sql sql-server tsql sql-server-2008 random


【解决方案1】:

试试这个:

select abs(checksum(newid()))%200

更新

这里发生了一些可疑的事情:

select 'Not in the range! This is impossible!' [Message]
where cast(CAST(CAST(CRYPT_GEN_RANDOM(2) AS int) AS float) / 65535 * 10  as int) 
not in (0,1,2,3,4,5,6,7,8,9)

点击F5,直到收到消息。

更新 2

此查询具有相同的效果:

select 'Not in the range! This is impossible!' [Message]
where abs(checksum(newid()))%10
not in (0,1,2,3,4,5,6,7,8,9)

更新 3

select N'WTF? Schrödinger''s cat!' [Message], *
from (select 0 union select 1) t(n)
join (select abs(checksum(newid()))%2 rnd) r(n) on t.n = r.n

最后一个查询有时可能返回 2 行,这实质上意味着 abs(checksum(newid()))%2 同时返回 0 和 1,这是不可能的,因为它包含在“仅选择一行”语句中,因此值会在稍后更新已加入。 :|然后连接再次发生,这令人震惊。

更新 4

在 Microsoft Connect 中是 a known bug。这是an insightful article 正在发生的事情。

【讨论】:

  • 感谢您提供的替代方案,我相信还有更多。但是你能解释一下 my 代码的奇怪效果吗?
  • 也许 OP 有充分的理由需要一个加密质量的随机数。
  • MS 说:“将这个错误关闭为‘无法修复’。”令人失望,但我理解他们的推理,尽管“允许优化改变程序的语义”听起来确实令人震惊!
猜你喜欢
  • 1970-01-01
  • 2022-10-02
  • 2011-11-01
  • 2016-09-03
  • 2011-05-16
  • 1970-01-01
  • 1970-01-01
  • 2011-10-10
  • 1970-01-01
相关资源
最近更新 更多