根据这篇文章,在SQL Server中生成随机值的正确方法是:
ABS(CHECKSUM(NewId())) % 14 -- Returns a value between 0 and 13
但是,在case语句中使用此表达式时,例如:
SELECT
CASE ABS(CHECKSUM(NEWID())) % 4
WHEN 0 THEN 'String A'
WHEN 1 THEN 'String B'
WHEN 2 THEN 'String C'
WHEN 3 THEN 'String D'
END AS RandomString -- Returns String A, B, C, D and NULLs.
FROM sys.all_objects
如本SQL小提琴所示,outputtet RandomString列包含一些NULL 。我发现可以将随机化表达式包装在CTE中,以避免输出中出现NULL,但是我仍然想知道为什么上面的代码返回NULL?
WITH RandomNumber AS (
SELECT ABS(CHECKSUM(NEWID())) % 4 AS N FROM sys.all_objects
)
SELECT TOP 100
CASE N
WHEN 0 THEN 'String A'
WHEN 1 THEN 'String B'
WHEN 2 THEN 'String C'
WHEN 3 THEN 'String D'
END AS RandomString -- Does not return any NULLs. Only String A, B, C and D.
FROM RandomNumber
我尝试使用略有不同的方法生成随机数,但结果是相同的:
CAST(RAND(CHECKSUM(NEWID())) * 4 AS INT) -- Returns a value between 0 and 3
这似乎是SQL Server 2014上的问题,我尚未在其他版本上对其进行测试。
NULL
之所以生成s,是因为无法保证特定表达式将被计算多少次。
您想要的是让SQL Server按照以下方式进行操作:
let x = GenerateRandomNumber()
if x = 1 then 'String 1'
if x = 2 then 'String 2'
if x = 3 then 'String 3'
if x = 4 then 'String 4'
(这里GenerateRandomNumber()
是ABS(CHECKSUM(NEWID())) % 4
); 但是SQL Server实际执行的操作是:
if GenerateRandomNumber() = 1 then 'String 1'
if GenerateRandomNumber() = 2 then 'String 2'
if GenerateRandomNumber() = 3 then 'String 3'
if GenerateRandomNumber() = 4 then 'String 4'
因此,只有NULL
在碰巧为一个特定的比较操作选择正确的随机数时,您才会获得非结果。
我认为即使使用CTE,也无法保证SQL Server不会生成上面的第二个代码块之类的东西。如果您想要一个稳定的,生成一次的随机数,则需要安排将该值存储在某个位置(例如,在表变量或临时表中)。
我专注于保证的原因是,您不想最终根据当前观察到的行为编写代码。当SQL Server 2008在我们正在使用该TOP 100 PERCENT ... ORDER BY
技巧的视图中停止对结果进行“排序”时,报告了很多“问题” –某些情况在2005和更早版本上发生了(大部分)起作用,但不再起作用。
同样,如果有人要求我提供一个返回数字的表达式,那么5
我可以向他们提供该表达式,DATEPART(day,GETUTCDATE())
并让他们在所需的任意数量的行上运行尽可能多的查询(在接下来的8小时内),但这并不意味着我d推荐它作为解决问题的方法。
而且,我们知道SQL Server在某些方面对评估顺序的决策可能会令人惊讶。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句