Antecedentes: Yo estaba tratando de conseguir algunos valores aleatorios 'hex', mientras que la creación de datos ficticios y se acercó con esta construcción:Extraño comportamiento de Case Construction
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
Cuando se ejecuta esto en mi instancia de SQL Server 2008 R2, Tengo bastantes registros 'huh':
result
------
huh
3
huh
huh
6
8
6
Realmente no entiendo por qué. lo que se espera que suceda es:
- para cada registro
NewID()
viene con un nuevo valor aleatoria Binary_Checksum()
calcula un entero en base a dicho valorABS()
hace que el valor positivo% 16
devuelve el resto de ese valor positivo si se dividiría entre 16, que entonces sería un valor entre 0 y 15- th e
CASE
construcción convierte el valor a un personaje relevante - Puesto que hay
WHEN
s para cada valor entre 0 y 15, laELSE
no deberían necesitar este
o al menos, eso es lo que yo creo que debería ocurrir ... pero es evidente que algo va mal en el camino ...
al hacer la misma cosa en un enfoque de dos pasos (a través de temp-tabla), se han ido los de huh ...
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
¿Alguien que entiende esto? Por lo que puedo decir, debería dar el mismo resultado (es de hecho copiar y pegar) independientemente de que lo haga directamente o mediante una tabla temporal ... Pero obviamente algo va mal si lo hago en una sola declaración.
PD: No necesito una "solución" para esto, ya tengo una solución alternativa (ver a continuación), simplemente estoy esperando que alguien me explique por qué hace lo que hace.
Solución:
SELECT TOP 100 result = SubString('abcdef', 1 + (ABS(Binary_Checksum(NewID())) % 16), 1)
FROM sys.objects
PD: si alguien puede probar esto en diferentes versiones de SQL-Server que podrían ser interesantes también ... – deroby
Su solución parece más sucinta que la original ... – Russell
Thx para explicar esto chicos ... yendo con Damiens respuesta ya que es un poco más detallado para cualquiera que pueda tropezar con esto. (y fue 1 minuto más rápido en la parte superior = P) – deroby