use*_*015 8 insert t-sql case checksum
当我为 70-461 考试而学习时,我正在 SSMS 中玩弄一些东西以学习更多知识,但我遇到了一些问题。我正在尝试创建一个表来使用,因此我不必更改/删除 AdventureWorks 或 TSQL2012 数据库中任何已创建的表。在实际创建要使用的表之前,我创建了一个临时表来测试我的代码,这是我用来将值插入表中的代码:
DECLARE @i INT = 1
WHILE @i < 10
BEGIN
INSERT INTO #TestEmployeeCountry
VALUES ( SUBSTRING('ABCDEFGHIJKLMNOP', @i, 1),
CASE (SELECT ABS(CHECKSUM(NEWID()))%10 +1)
WHEN 1 THEN 'USA'
WHEN 2 THEN 'CANADA'
WHEN 3 THEN 'MEXICO'
WHEN 4 THEN 'UK'
WHEN 5 THEN 'FRANCE'
WHEN 6 THEN 'SPAIN'
WHEN 7 THEN 'RUSSIA'
WHEN 8 THEN 'CHINA'
WHEN 9 THEN 'JAPAN'
WHEN 10 THEN 'INDIA'
END)
SET @i = @i + 1
END;
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是我不断收到错误消息“无法将值 NULL 插入列 'Country'、表 'tempdb.dbo.#TestEmployeeCountry” 这是因为我将 Country 列设置为 NOT NULL,并且我的代码确实适用于某些插入,问题是我从我的 case 语句中随机获得了 NULL 值。
我知道要解决这个问题,我可以轻松添加另一行,上面写着“DEFAULT xxxxxx”,但是我想了解发生了什么,因为根据我所看到的,我不应该这样做,是吗?我以为我写的 case 语句是正确的,只给了我一个 1-10 之间的数字,并且在测试超过 1000 次尝试的特定选择语句时,我总是得到一个 1-10 之间的随机数,没有更大或更小。谁能帮我理解为什么这段代码试图在该列中输入一个 NULL 值?
@PaulWhite 在 SO 问题中已经回答了为什么会发生这种情况:这个 CASE 表达式如何到达 ELSE 子句?
要解决它,您应该计算语句的ABS(CHECKSUM(NEWID()))%10 +1外部/之前,INSERT以便计算一次。就像是:
DECLARE @i INT = 1 ;
DECLARE @rand INT ;
WHILE @i <= 10
BEGIN
SET @rand = ABS(CHECKSUM(NEWID()))%10 +1 ;
INSERT INTO TestEmployeeCountry
VALUES ( SUBSTRING('ABCDEFGHIJKLMNOP', @i, 1),
CASE @rand
WHEN 1 THEN 'USA'
WHEN 2 THEN 'CANADA'
WHEN 3 THEN 'MEXICO'
WHEN 4 THEN 'UK'
WHEN 5 THEN 'FRANCE'
WHEN 6 THEN 'SPAIN'
WHEN 7 THEN 'RUSSIA'
WHEN 8 THEN 'CHINA'
WHEN 9 THEN 'JAPAN'
WHEN 10 THEN 'INDIA'
END) ;
SET @i = @i + 1 ;
END ;
Run Code Online (Sandbox Code Playgroud)
另请注意,使用您的代码,10 个国家/地区不会以相等的概率出现在表中!第一个国家 ( USA) 将有 10% 的机会,第二个将有 9% ( (100%-10%)*10%),第三个 8.1%, ( (100%-19%)*10%) 等等。这留下了不小的机会(大约1/e)以至于 10 个国家都没有被选中,CASE表达式转到默认值ELSE NULL,您会收到错误消息。(如果您允许列中的空值并运行SQLfiddle 脚本,您可以检查概率。)
根据上述,另一种解决方法是更改表达式以符合 SQL-Server 的执行方式,CASE并且所有 10 种情况都具有相同的概率:
CASE 0
WHEN ABS(CHECKSUM(NEWID()))%10 THEN 'USA'
WHEN ABS(CHECKSUM(NEWID()))%9 THEN 'CANADA'
WHEN ABS(CHECKSUM(NEWID()))%8 THEN 'MEXICO'
WHEN ABS(CHECKSUM(NEWID()))%7 THEN 'UK'
WHEN ABS(CHECKSUM(NEWID()))%6 THEN 'FRANCE'
WHEN ABS(CHECKSUM(NEWID()))%5 THEN 'SPAIN'
WHEN ABS(CHECKSUM(NEWID()))%4 THEN 'RUSSIA'
WHEN ABS(CHECKSUM(NEWID()))%3 THEN 'CHINA'
WHEN ABS(CHECKSUM(NEWID()))%2 THEN 'JAPAN'
ELSE 'INDIA'
END
Run Code Online (Sandbox Code Playgroud)