Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 И снова косяки от Microsoft  [new]
Jaffar
Member

Откуда:
Сообщений: 633
выражение cast((RAND() * count(*) over()) as int) - иногда может принимать значение = 0 - это нормально
НО функция NULLIF(0, 0) - должна возвращать NULL, и возвращать 0 с такими аргументами в принципе не должна,
однако следующий запрос говорит об обратном

declare @I int, @J int

set @I = -1
set @J =  0


while( @I != 0)
begin
	select @I = IsNULL(NULLIF(cast((RAND() * count(*) over()) as int), 0), 1)
	from sys.objects t

	set @J = @J + 1
end

select @I '@I === 0', @J '@J'


Посмотрел вот тут http://msdn.microsoft.com/ru-ru/library/ms177562.aspx:


"В функции NULLIF не рекомендуется использовать такие зависимые от времени функции, как RAND().
Это может приводить к тому, что функция будет вычисляться дважды с возвратом различных результатов для каждого из вызовов. " - ну это понятно т.к. RAND() зависит от времени.

Чем объяснить такое свинское поведение?
22 ноя 13, 07:20    [15171871]     Ответить | Цитировать Сообщить модератору
 Re: И снова косяки от Microsoft  [new]
Jaffar
Member

Откуда:
Сообщений: 633
Версия:

Microsoft SQL Server 2012 - 11.0.2100.60 (X64)
Feb 10 2012 19:39:15
Copyright (c) Microsoft Corporation
Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)
22 ноя 13, 07:22    [15171873]     Ответить | Цитировать Сообщить модератору
 Re: И снова косяки от Microsoft  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31779
Jaffar
Это может приводить к тому, что функция будет вычисляться дважды с возвратом различных результатов для каждого из вызовов
Ну что, просто косой код у МС, причём даже описанный в документации.

Не понимаю, зачем вычислять дважды аргумент и почему это за десятилетия не сделано нормально...
22 ноя 13, 07:33    [15171888]     Ответить | Цитировать Сообщить модератору
 Re: И снова косяки от Microsoft  [new]
Jaffar
Member

Откуда:
Сообщений: 633
т.е. функция NULLIF в С++ нотации имеет примерно такой вид:

void NULLIF(expr1, expr2)
{
  if(value(expr1) = value(expr2)) return(NULL)
  else return(value(expr1))
}

и соотв. для RAND() ,будет иметь такой вид:
void NULLIF(expr1, expr2)
{
  if(value(RAND()) = value(expr2)) return(NULL)
  else return(value(RAND()))
}
--- т.е. все функции из expr1 - вызываются 2 раза 
--- тоже самое наверное будет справедливо и для newID() и для getdate()

----
на мой взгляд д.б. как-то так:
void NULLIF(expr1, expr2)
{
 declare @val1 void, @val2 void
 set @val1 = value(expr1)
 set @val2 = value(expr2)
 
  if(@val1 = @val2) return(NULL)
  else return(@val1)
}
22 ноя 13, 08:35    [15171995]     Ответить | Цитировать Сообщить модератору
 Re: И снова косяки от Microsoft  [new]
Jaffar
Member

Откуда:
Сообщений: 633
т.е. тоже самое справедливо и для функции IsNULL и т.п.?
ведь она тоже хотябы разок да должна вычислить значение expr1




чтобы победить такое поведение -

нужно использовать RAND() так

select *
from TABLE_1
cross apply(select RAND() RANDX) t2
22 ноя 13, 08:56    [15172056]     Ответить | Цитировать Сообщить модератору
 Re: И снова косяки от Microsoft  [new]
daw
Member

Откуда: Муром -> Москва
Сообщений: 7381
Jaffar,

для isnull, вроде бы, не наблюдалось такого.
а nullif - она в плане через case раскрывается, причем, это Searched CASE. да, примерно так, как вы расписали:
[Expr1041] = Scalar Operator(isnull(CASE WHEN CONVERT(int,rand()*CONVERT_IMPLICIT(float(53),[Expr1039],0),0)=(0) THEN NULL ELSE CONVERT(int,rand()*CONVERT_IMPLICIT(float(53),[Expr1040],0),0) END,(1)))


кстати, simple case
BOL
Simple CASE expression:
CASE input_expression
WHEN when_expression THEN result_expression [ ...n ]
[ ELSE else_result_expression ]
END

тоже раскрывается через searched. была, помнится, темка:
https://www.sql.ru/forum/548590/pravilo-bag-ili-ficha
22 ноя 13, 09:50    [15172284]     Ответить | Цитировать Сообщить модератору
 Re: И снова косяки от Microsoft  [new]
Гость333
Member

Откуда:
Сообщений: 3683
daw
для isnull, вроде бы, не наблюдалось такого

Да, для isnull такого нет. Потому что в MSSQL есть внутренняя функция isnull, которая показывается в планах запросов.

А для coalesce — наблюдается, т.к. он тоже раскрывается в case, как и nullif.

То есть nullif, coalesce — суть синтаксический сахар. В отличие от isnull.
22 ноя 13, 12:19    [15173167]     Ответить | Цитировать Сообщить модератору
 Re: И снова косяки от Microsoft  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31779
Гость333
А для coalesce — наблюдается, т.к. он тоже раскрывается в case, как и nullif.

То есть nullif, coalesce — суть синтаксический сахар. В отличие от isnull.
Ну так сахар с багой. Раскрывать то нужно правильно, присвоив выражение какому нибуть [ExprNNNN], а потом уже его в CASE
22 ноя 13, 12:33    [15173290]     Ответить | Цитировать Сообщить модератору
 Re: И снова косяки от Microsoft  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6723
Jaffar
Чем объяснить такое свинское поведение?
M$ такой M$.

Errors in the topic of coalesce()
COALESCE((subquery), 1) may return NULL
NULLIF works incorrectly with non-deterministic functions such as RAND()

Голосуем независимо от состояния.
Ставим комментарии.
22 ноя 13, 18:29    [15176325]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить