ВЫБОР СЛУЧАЯ против СЛУЧАЯ В SQL

#sql-server #sql-server-2008 #tsql

#sql-сервер #sql-server-2008 #tsql

Вопрос:

Я не совсем понимаю, почему эти два разных codesamples возвращают другое значение.

каким-то образом неправильный, но рабочий синтаксис возвращает ложные результаты, например, он возвращается, 0 когда сравнение выполняется по двум равным значениям:

 (SELECT CASE 
    WHEN 
       SUM(V.IsCompatible) OVER 
          (PARTITION BY ComputerName, UserID) = ApplicationCount 
    THEN 1 ELSE 0 END
) AS CompatibleUser
  

Приведенный ниже возвращает правильные значения, т.Е. 1 когда сравниваются два равных значения.

 (CASE 
    WHEN 
       SUM(V.IsCompatible) OVER 
         (PARTITION BY ComputerName, UserID) = ApplicationCount 
    THEN 1 ELSE 0 END
) AS CompatibleUser
  

или еще проще:

 (SELECT CASE 
    WHEN 
       X = Y 
    THEN 1 ELSE 0 END
) AS Result
  

X = 22 И Y = 22 => Результат = 0

 (CASE 
    WHEN 
       X = Y 
    THEN 1 ELSE 0 END
) AS Result
  

X = 22 И Y = 22 => Результат = 1

Я понимаю, что важно применять правильный синтаксис, и я осведомлен о синтаксисе ВЫБОРА СЛУЧАЯ в T-SQL, но я не понимаю, как первый пример кода оценивается и выдает неожиданный результат.

обновление: полный запрос в его контексте

 select userapplication.username,
   computerdetails.computername,
   sum(userapplication.iscompatible) 
       over (partition by computerdetails.computername, 
                          userapplication.userid) as compatiblecount,
   userapplication.applicationcount,
   ( case
       when sum(userapplication.iscompatible) 
           over (partition by 
           computerdetails.computername, 
           userapplication.userid) <> userapplication.applicationcount 
       then 0
       else 1
     end 
   ) as usercomputeriscompatible
from   computerdetails
   right outer join usercomputer
     on computerdetails.computerid = usercomputer.computerid
   right outer join userapplication
     on usercomputer.gebruikerid = userapplication.userid 
  

итак userComputerIsCompatible , о каком результате идет речь здесь

Комментарии:

1. Возможно, вам придется показать больше вашего запроса. Используются ли эти примеры в SELECT предложении, WHERE предложении, HAVING clause, где-нибудь еще?

2. Я добавил запрос (немного измененный в именовании), но он представляет, как он работает

Ответ №1:

Я думаю, что причина такого поведения заключается в следующем: выражения типа (SELECT ...) считаются вложенными запросами, даже если у них нет FROM предложения. Предполагается, что источником данных для этих (ложных) «подзапросов» является только текущая строка. Таким образом, (SELECT expression) интерпретируется как (SELECT expression FROM current_row) и (SELECT SUM(iscompatible)OVER(...)) выполняется как (SELECT SUM(iscompatible)OVER(current_row)) .

Аргумент: анализ плана выполнения для (SELECT SUM(IsWeb) OVER(PARTITION BY OrderDate) [FROM current_row]) выражения введите описание изображения здесь

Я вижу Constant Scan (сканирую внутреннюю таблицу констант) оператор вместо Clustered Index Scan перед Segment и Stream Aggregate ( [Expr1007] = Scalar Operator(SUM(@OrderHeader.[IsWeb] as [h].[IsWeb])) ) операторов. Эта внутренняя таблица ( Constant Scan ) создается из текущей строки.

Пример (протестирован с SQL2005SP3 и SQL2008):

 DECLARE @OrderHeader TABLE
(
     OrderHeaderID  INT IDENTITY PRIMARY KEY
    ,OrderDate      DATETIME NOT NULL
    ,IsWeb          TINYINT NOT NULL --or BIT
);
INSERT  @OrderHeader 
SELECT  '20110101', 0
UNION ALL 
SELECT  '20110101', 1
UNION ALL
SELECT  '20110101', 1
UNION ALL 
SELECT  '20110102', 1
UNION ALL
SELECT  '20110103', 0
UNION ALL
SELECT  '20110103', 0;

SELECT  *
        ,SUM(IsWeb) OVER(PARTITION BY OrderDate) SumExpression_1
FROM    @OrderHeader h
ORDER BY h.OrderDate;

SELECT  *
        ,(SELECT SUM(IsWeb) OVER(PARTITION BY OrderDate)) SumWithSubquery_2
FROM    @OrderHeader h
ORDER BY h.OrderDate;
  

Результаты:

 OrderHeaderID OrderDate               IsWeb SumExpression_1
------------- ----------------------- ----- ---------------
1             2011-01-01 00:00:00.000 0     2
2             2011-01-01 00:00:00.000 1     2
3             2011-01-01 00:00:00.000 1     2
4             2011-01-02 00:00:00.000 1     1
5             2011-01-03 00:00:00.000 0     0
6             2011-01-03 00:00:00.000 0     0

OrderHeaderID OrderDate               IsWeb SumWithSubquery_2
------------- ----------------------- ----- -----------------
1             2011-01-01 00:00:00.000 0     0
2             2011-01-01 00:00:00.000 1     1
3             2011-01-01 00:00:00.000 1     1
4             2011-01-02 00:00:00.000 1     1
5             2011-01-03 00:00:00.000 0     0
6             2011-01-03 00:00:00.000 0     0
  

Комментарии:

1. 1 Согласен, SELECT SUM(IsWeb) OVER(PARTITION BY OrderDate) явно применяется только к столбцам текущей строки, поэтому всегда будет иметь любое значение IsWeb в этой строке.

Ответ №2:

Я попробовал ваш код, и я получаю одинаковые результаты для обоих запросов. Вот код, который я пробовал:

 DECLARE @X INT = 22
DECLARE @Y INT = 22

SELECT (SELECT CASE 
    WHEN 
       @X = @Y 
    THEN 1 ELSE 0 END
) AS Result

SELECT (CASE 
    WHEN 
       @X = @Y 
    THEN 1 ELSE 0 END
) AS Result
  

Результат — 1 и 1

Я запустил это на SQL Server 2008 R2

Комментарии:

1. 1: Сделал то же самое сам, и результаты действительно равны и правильны .

2. На мой взгляд, реальная проблема заключается не в том, CASE ... END а в том, SUM(V.IsCompatible) как (SELECT SUM... no_FROM_clause) вычисляется в этих двух случаях: (SUM...) и,,,.