【问题标题】:CHOOSE() not working as intended [duplicate]CHOOSE() 未按预期工作[重复]
【发布时间】:2014-05-20 20:05:48
【问题描述】:

当我将随机整数生成与CHOOSE() 结合使用时,我得到了意想不到的NULL 值。

以下应该只返回字母a-e,而不是NULL也包含在值中:

查询:

;WITH cte AS (SELECT 1 RN
              UNION  ALL 
              SELECT RN + 1 
              FROM cte
              WHERE RN < 100)
SELECT DISTINCT CHOOSE(1 + ABS(CRYPT_GEN_RANDOM(8)%5),'a','b','c','d','e','f')
FROM cte

结果:

NULL
a
b
c
d
e

预期结果:

a
b
c
d
e

随机数生成按预期工作,仅返回值 1-5:

;WITH cte AS (SELECT 1 RN
              UNION  ALL 
              SELECT RN + 1 
              FROM cte
              WHERE RN < 50)
SELECT 1 + ABS(CRYPT_GEN_RANDOM(8)%5)
FROM cte

演示:SQL Fiddle

CHOOSE() 工作方式如下(索引从 1 开始):

SELECT CHOOSE(3,'dog','cat','horse','fish')  
-- horse
SELECT CHOOSE(8,'dog','cat','horse','fish')  
-- NULL

在函数中使用随机数生成适用于LEFT()RIGHT()CHAR() 等。 一个解决方法会很好,但大多数时候我很好奇为什么我会得到NULL 值。

【问题讨论】:

  • 有趣的是,如果您将DISTINCT 1 + ABS(CRYPT_GEN_RANDOM(8)%5) 移动到子查询中并在CHOOSE 中使用该子查询中的列,您不会得到空值。
  • @GSerg 我也注意到了这一点,遗憾的是,我在SELECT 中使用了多个CRYPT_GEN_RANDOM(),每个都会生成一个随机数。即:SELECT 1 + ABS(CRYPT_GEN_RANDOM(8)%5), 1 + ABS(CRYPT_GEN_RANDOM(8)%5), 1 + ABS(CRYPT_GEN_RANDOM(8)%5) 我可以在我的 cte 中将其中的一些称为不同的列,但这并不理想。
  • @GoatCO 您需要在“理想”和“按预期”之间进行选择。这就是 SQL Server 的工作方式;无论 SQL Server 的设计是否适合您,您都需要解决它。顺便说一句,我将其标记为重复,因为 CHOOSE() 扩展为 CASE 表达式,因此其行为与 Paul 在副本中描述的完全一样。更多在我的 cmets 下面。
  • @AaronBertrand 同意,知道这是设计使然,无论方便如何,都可以轻松解决它。关于它被标记为重复,虽然链接的答案肯定有帮助,但只有在理解 CHOOSE()CASE 在后端的处理方式完全相同时才会有所帮助。
  • 不,他们没有,或者至少他们不应该 - 重复是谷歌果汁。 Background

标签: sql sql-server-2012


【解决方案1】:

这很奇怪,可能属于错误类别。当然,您所做的事情很奇怪,因为您将随机的位模式视为一个数字。应该是有效的,但可能会产生意想不到的后果。而且,这不是溢出问题。它与8 的其他值一起出现。

见证以下内容(SQL Fiddle):

WITH cte AS (SELECT 1 RN
              UNION  ALL 
              SELECT RN + 1 
              FROM cte
              WHERE RN < 100)
SELECT  CHOOSE(1 + ABS(n),'a','b','c','d','e','f'),
        CHOOSE(1 + abs(CRYPT_GEN_RANDOM(8)%5),'a','b','c','d','e','f')
FROM (select abs(CRYPT_GEN_RANDOM(8)%5) as n
      from cte
     ) n
order by 1

第一列是从不 NULL。第二列是定期NULL。换句话说,如果您将值分配给另一个变量,它会有所不同。我可以想象一些 8 字节大整数的模式代表 NaN,但这种情况发生得并不多。

鉴于直接调用失败但存在中间变量时有效,我得出的结论是这可能是某种错误。我想知道它是否记录在某个地方。

【讨论】:

  • 不是错误。 CHOOSE 扩展为 CASE 表达式,并且在 CASE 表达式中,为每个潜在输出重新评估 CRYPT_GEN_RANDOM。很明显,第一次评估会产生 2,接下来的 5 次会产生 1,将您推向 ELSE 领域。 Paul demonstrates this with CHECKSUM(NEWID()) here, but the concept is the same.
  • 不,它每次都评估它,不是case arg1 when 1 then val1 when 2 then val2而是case when arg1 = 1 then val1 when arg1 = 2 then val2
  • arg1 是在每种情况下对函数的不同评估
  • 我不认为“实施被故意破坏”。我认为几年前就做出了设计决定,而您只是不喜欢这个决定。 :-) CHOOSE() 不提供任何新功能,而且COALESCE() 也不提供。他们都只是利用现有的CASE 表达式 行为。
  • @AaronBertrand 。 . .这两个功能引入了不必要的问题。我猜 ANSI 对coalesce() 中的多重评估没有什么要说的,但是当isnull() 按预期工作(但只是在两个参数上)时,这种行为似乎很奇怪。顺便说一句,我在这里想念你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-20
  • 2018-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-07
  • 2019-10-10
相关资源
最近更新 更多