Reputation: 264
I am using the very same windowing function in multiple WHEN in a T-SQL SELECT.
SELECT
ModuleUsage = CASE
WHEN Operation = 1 and OperationResult=1 and 1 != LAG(operation) OVER(
PARTITION BY moduleid, clientname
ORDER BY moduleid, clientname, timestamp, operation
)
THEN 1
WHEN Operation = 2 and OperationResult=3 and 1 = LAG(operation) OVER(
PARTITION BY moduleid, clientname
ORDER BY moduleid, clientname, timestamp, operation
)
THEN -1
ELSE 0
END
, *
FROM [dbo].[LicencesTracing]
Is it evaluated twice or does the query optimizer reuse the result the second time? Thanks in advance
Upvotes: 2
Views: 1500
Reputation: 7918
You can determine if your Window function is being evaluated once or more by looking at the actual execution plan (e.g. run the query with "include actual execution plan" turned on).
If you have an index in place to support that window function then it really does not matter much as the operation is inexpensive. A POC index would be very helpful for this query. The index would look like this:
CREATE nonclustered index xxx on dbo.LicencesTracing(moduleid, clientname, timestamp, operation)
INCLUDE <whatever columns you are returning>;
You could simplify your query and force the optimizer to evaluate the Window function by calculating it in a subquery; something like this: (note that I can't test this...)
SELECT ModuleUsage = CASE
WHEN Operation = 1 and OperationResult = 1 and lagOp <> 1 THEN 1
WHEN Operation = 2 and OperationResult = 3 and lagOp = 1 THEN -1 ELSE 0
END
FROM
(
SELECT Operation, OperationResult, lagOp =
LAG(operation) OVER(PARTITION BY moduleid, clientname
ORDER BY moduleid, clientname, timestamp, operation), *
FROM [dbo].[LicencesTracing]
) sub;
Upvotes: 1
Reputation: 43636
Could we rewrite the query like below in order to have the function only one time?
-- window function <> 1
SELECT CASE WHEN LAG(operation) OVER(PARTITION BY moduleid, clientname ORDER BY moduleid, clientname, timestamp, operation) <> 1
THEN CASE WHEN Operation = 1 and OperationResult=1 THEN 1 ELSE 0 END
-- window function = 1
ELSE
CASE WHEN Operation = 2 and OperationResult=3 THEN -1 ELSE 0 END
END AS ModuleUsage
,*
FROM [dbo].[LicencesTracing];
And I thing using IIF
will simplify the code:
SELECT CASE WHEN LAG(operation) OVER(PARTITION BY moduleid, clientname ORDER BY moduleid, clientname, timestamp, operation) <> 1
THEN IIF(Operation = 1 and OperationResult=1, 1, 0)
ELSE IIF(Operation = 2 and OperationResult=3, -1, 0)
END AS ModuleUsage
,*
FROM [dbo].[LicencesTracing];
Upvotes: 1