#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...)
и,,,.