我需要将一些测试数据加载到Account表的Channel字段中。频道可以是10个不同值中的一个,所以我想我会使用CASE
表达式和ABS(CHECKSUM(NewId())) % 10
随机分配频道中的一个值,如下所示:
SELECT
id,
name,
Channel =
CASE ABS(CHECKSUM(NewId())) % 10
WHEN 0 THEN 'Baby Only'
WHEN 1 THEN 'Club'
WHEN 2 THEN 'Drug'
WHEN 3 THEN 'Food'
WHEN 4 THEN 'Internet'
WHEN 5 THEN 'Liquidators'
WHEN 6 THEN 'Mass'
WHEN 7 THEN 'Military'
WHEN 8 THEN 'Other'
WHEN 9 THEN 'Speciality'
ELSE '*NONE*' -- How is this ever getting reached?
END
FROM
retailshelf_nil...account A
由于我使用modulo 10,我认为唯一可能的值应该是0-9。但是当我运行上面的代码时,我发现确实正在达到ELSE
子句,并且我的数据在某些记录中显示为'NONE',如下所示:
id name Channel
001L000000KpgFqIAJ Acct1 *NONE*
001L000000KpgFrIAJ Acct2 Mass
001L000000KpgFsIAJ Acct3 Club
001L000000KpgFtIAJ Acct4 *NONE*
001L000000KpgFuIAJ Acct5 Baby Only
001L000000KpgFvIAJ Acct6 *NONE*
001L000000KpgFwIAJ Acct7 Mass
有人可以解释一下我允许ELSE条款到达的逻辑错误吗?
当我运行一个简单的测试来生成如下的随机数时:
SELECT
RadomNum = ABS(CHECKSUM(NewId())) % 10
FROM
retailshelf_nil...account A
ORDER BY
1
生成的所有数字都是0-9,正如预期的那样,那么第一个SQL有什么不同?
是否有确保永远不会达到ELSE
的解决方法?
答案 0 :(得分:44)
查询的书面形式扩展为:
Channel =
CASE
WHEN ABS(CHECKSUM(NewId())) % 10 = 0 THEN 'Baby Only'
WHEN ABS(CHECKSUM(NewId())) % 10 = 1 THEN 'Club'
WHEN ABS(CHECKSUM(NewId())) % 10 = 2 THEN 'Drug'
WHEN ABS(CHECKSUM(NewId())) % 10 = 3 THEN 'Food'
WHEN ABS(CHECKSUM(NewId())) % 10 = 4 THEN 'Internet'
WHEN ABS(CHECKSUM(NewId())) % 10 = 5 THEN 'Liquidators'
WHEN ABS(CHECKSUM(NewId())) % 10 = 6 THEN 'Mass'
WHEN ABS(CHECKSUM(NewId())) % 10 = 7 THEN 'Military'
WHEN ABS(CHECKSUM(NewId())) % 10 = 8 THEN 'Other'
WHEN ABS(CHECKSUM(NewId())) % 10 = 9 THEN 'Speciality'
ELSE '*NONE*' -- How is this ever getting reached?
END
每次测试都会使用NEWID
的新值。
答案 1 :(得分:5)
将为每个WHEN子句计算一个新的“随机”数字 - 您可以改为使用派生表:
SELECT ID, Name,
Channel =
CASE Rand
WHEN 0 THEN 'Baby Only'
WHEN 1 THEN 'Club'
WHEN 2 THEN 'Drug'
WHEN 3 THEN 'Food'
WHEN 4 THEN 'Internet'
WHEN 5 THEN 'Liquidators'
WHEN 6 THEN 'Mass'
WHEN 7 THEN 'Military'
WHEN 8 THEN 'Other'
WHEN 9 THEN 'Speciality'
ELSE '*NONE*' -- How is this ever getting reached?
END
FROM
( SELECT
id,
name,
ABS(CHECKSUM(NewId())) % 10 Rand
FROM
retailshelf_nil...account A
) zzz;
或CROSS APPLY子查询:
SELECT A.ID, A.Name,
Channel =
CASE zzz.Rand
WHEN 0 THEN 'Baby Only'
WHEN 1 THEN 'Club'
WHEN 2 THEN 'Drug'
WHEN 3 THEN 'Food'
WHEN 4 THEN 'Internet'
WHEN 5 THEN 'Liquidators'
WHEN 6 THEN 'Mass'
WHEN 7 THEN 'Military'
WHEN 8 THEN 'Other'
WHEN 9 THEN 'Speciality'
ELSE '*NONE*' -- How is this ever getting reached?
END
FROM
retailshelf_nil...account A
CROSS APPLY
( SELECT
ABS(CHECKSUM(NewId())) % 10
) zzz (Rand);
这样每条记录只调用一次NewID()
。
类似的痤疮已解决here。
T-SQL documentation解释了这种现象(授予它适用于Sybase,但显然仍然适用于SQL Server):
引用
rand
函数,getdate
函数的表达式, 等等,每次评估时都会产生不同的值。这个 在某些情况下使用这些表达式时会产生意外结果 案例表达。例如,SQL标准指定了这种情况 表达式:case expression when value1 then result1 when value2 then result2 when value3 then result3 ... end
等同于以下形式的case表达式:
case expression when expression=value1 then result1 when expression=value2 then result2 when expression=value3 then result3 ... end
答案 2 :(得分:0)
与第二个问题相关,
CHECKSUM(NewId())有时会返回否定结果,这与任何case
条件都不匹配。如果负数除以任何数字,结果将为负数。执行以下查询
declare @v nvarchar(50) = newid()
select CHECKSUM(@v),@v,CHECKSUM(@v) % 10