背景:我在创建虚拟数据时尝试获取一些随机的“十六进制”值,并提出了这种结构:
SELECT TOP 100
result = (CASE ABS(Binary_Checksum(NewID())) % 16
WHEN -1 THEN 'hello'
WHEN 0 THEN '0'
WHEN 1 THEN '1'
WHEN 2 THEN '2'
WHEN 3 THEN '3'
WHEN 4 THEN '4'
WHEN 5 THEN '5'
WHEN 6 THEN '6'
WHEN 7 THEN '7'
WHEN 8 THEN '8'
WHEN 9 THEN '9'
WHEN 10 THEN 'a'
WHEN 11 THEN 'b'
WHEN 12 THEN 'c'
WHEN 13 THEN 'd'
WHEN 14 THEN 'e'
WHEN 15 THEN 'f'
ELSE 'huh' END)
FROM sys.objects
在我的SQL Server 2008 R2实例上运行时,我收到了很多'huh'记录:
result
------
huh
3
huh
huh
6
8
6
我真的不明白为什么。 我期望发生的是:
NewID()
提供了一个新的随机值Binary_Checksum()
根据上述值计算一个int ABS()
使值为正% 16
如果将除以16,则返回该正值的余数,然后该值将介于0和15之间CASE
构造将值转换为相关字符WHEN
,因此永远不需要ELSE
或者至少,这是我认为应该发生的事情......但显然在路上出了问题......
当采用两步法(通过临时表)做同样的事情时,哼哼... ...
SELECT TOP 100 x = ABS(Binary_Checksum(NewID())) % 16,
result = 'hello'
INTO #test
FROM sys.objects
UPDATE #test
SET result = (CASE x WHEN 0 THEN '0' WHEN 1 THEN '1' WHEN 2 THEN '2' WHEN 3 THEN '3'
WHEN 4 THEN '4' WHEN 5 THEN '5' WHEN 6 THEN '6' WHEN 7 THEN '7'
WHEN 8 THEN '8' WHEN 9 THEN '9' WHEN 10 THEN 'a' WHEN 11 THEN 'b'
WHEN 12 THEN 'c' WHEN 13 THEN 'd' WHEN 14 THEN 'e' WHEN 15 THEN 'f'
ELSE 'huh' END)
SELECT * FROM #test
任何明白这一点的人?据我所知,它应该给出相同的结果(它确实是复制粘贴),不管我是直接做什么还是通过临时表...但是如果我在一个语句中这样做,显然会出现问题。< / p> PS:我不需要'修复',我已经有一个解决方法(见下文),我只是希望有人可以解释我为什么这样做。
解决方法:
SELECT TOP 100 result = SubString('0123456789abcdef', 1 + (ABS(Binary_Checksum(NewID())) % 16), 1)
FROM sys.objects
答案 0 :(得分:8)
计划中的计算标量具有以下公式
[Expr1038] =标量运算符(CASE WHEN abs(binary_checksum(newid()))%(16)=( - 1)THEN'hello'ELSE CASE WHEN abs(binary_checksum(newid()))%(16)=(0)那么'0'是的情况下 abs(binary_checksum(newid()))%(16)=(1)那么'1'是的情况下 abs(binary_checksum(newid()))%(16)=(2)THEN'2'ELE CASE WHEN abs(binary_checksum(newid()))%(16)=(3)那么'3'是的情况下 abs(binary_checksum(newid()))%(16)=(4)那么'4'是的情况下 abs(binary_checksum(newid()))%(16)=(5)那么'5'是的情况下 abs(binary_checksum(newid()))%(16)=(6)那么'6'是的情况下 abs(binary_checksum(newid()))%(16)=(7)那么'7'是的情况下 abs(binary_checksum(newid()))%(16)=(8)那么'8'是的情况下 abs(binary_checksum(newid()))%(16)=(9)那么'9'是的情况下 abs(binary_checksum(newid()))%(16)=(10)那么'a'过的情况下 abs(binary_checksum(newid()))%(16)=(11)那么'''''''''' abs(binary_checksum(newid()))%(16)=(12)THEN'c'ELE CASE WHEN abs(binary_checksum(newid()))%(16)=(13)然后''''''' abs(binary_checksum(newid()))%(16)=(14)那么'''是的情况下 abs(binary_checksum(newid()))%(16)=(15)那么'f'ELSE'huh'END END END END END END END END END END END END END END END END END END END)
重复评估随机数而不是评估一次,并在CASE
语句的每个分支中保持不变。
Damien的答案中提出的(固定的)解决方案对我有用
SELECT TOP 100
result = (CASE ABS(Binary_Checksum(Value)) % 16
WHEN -1 THEN 'hello'
/*...*/
ELSE 'huh' END)
FROM (select NewID() as Value,* from sys.objects ) so
因为该计划有2个计算标量运算符。第一个定义
[Expr1038] = Scalar Operator(newid())
然后将常量表达式Expr1038
输入CASE
表达式。我不确定这种行为是绝对保证的。它可能受到优化者的一时兴起。
答案 1 :(得分:3)
我认为,与simple CASE expression的描述相反,它实际上为每个input_expression
比较重新评估input_expression = when_expression
(这通常是安全的,除非,如此例如,input_expression
)
因此,会发生的事情是,每次比较时,它会在0到15之间生成不同的随机数,如果在16次评估/比较之后,它从未生成匹配的数字,则huh
会出现。
这不会生成huh
s:
SELECT TOP 100
result = (CASE ABS(Binary_Checksum(Value)) % 16
WHEN -1 THEN 'hello'
WHEN 0 THEN '0'
WHEN 1 THEN '1'
WHEN 2 THEN '2'
WHEN 3 THEN '3'
WHEN 4 THEN '4'
WHEN 5 THEN '5'
WHEN 6 THEN '6'
WHEN 7 THEN '7'
WHEN 8 THEN '8'
WHEN 9 THEN '9'
WHEN 10 THEN 'a'
WHEN 11 THEN 'b'
WHEN 12 THEN 'c'
WHEN 13 THEN 'd'
WHEN 14 THEN 'e'
WHEN 15 THEN 'f'
ELSE 'huh' END)
FROM (select NewID() as Value,* from sys.objects ) so