The value is returned instead of NULL when using function with OUTER APPLY

时光毁灭记忆、已成空白 提交于 2019-12-04 00:34:08

This is a very interesting query. The behaviour of your first query depends upon whether you use OPTION (RECOMPILE) or not.

As you point out, this:

DECLARE @u CHAR(12) = '066BDLER'
SELECT a.user_name, is_v.user_name 
FROM (SELECT @u AS user_name) a
OUTER APPLY [dbo].[vendor_relation_users](@u) AS is_v

returns this:

user_name       user_name
066BDLER        066BDLER

but if you add OPTION (RECOMPILE) like this:

SELECT a.user_name, is_v.user_name 
FROM (SELECT @u AS user_name) a
OUTER APPLY [dbo].[vendor_relation_users](@u) AS is_v
OPTION (RECOMPILE)   

you correctly get this:

user_name       user_name
066BDLER        NULL

I suspect this is due to a bug in how the query optimiser short circuits these inline functions due to cardinality estimates. If you look at the query plan for the two queries you will see that the one without the OPTION RECOMPILE just returns a constant.

I guess it is old bug described here. And it is Closed as Won't Fix

Please use this function like:

SELECT a.user_name, is_v.user_name 
FROM (SELECT @u AS user_name) a
OUTER APPLY (
    SELECT *
    FROM [dbo].[vendor_relation_users](a.user_name) 
    ) AS is_v

UPDATE#1

Just read the comments:

Might be the same basic issue as here stackoverflow.com/a/32414450/73226 – Martin Smith

That is it! Same issue, same link I have provided to MS Connect site.

UPDATE#2

Instead:

RETURN (SELECT @user_name AS user_name WHERE @user_name NOT LIKE '06%');

You need to use:

RETURN (SELECT CASE WHEN @user_name LIKE '06%' THEN NULL ELSE @user_name END)
CREATE FUNCTION [dbo].[vendor_relation_users]
(
    @user_name CHAR(12)
)
RETURNS TABLE
AS
  RETURN (SELECT CASE WHEN @user_name NOT LIKE '06%' THEN  @user_name  ELSE NULL END as [user_name]);  
GO

Ok, https://docs.microsoft.com/en-us/sql/t-sql/language-elements/select-local-variable-transact-sql

If the SELECT statement returns no rows, the variable retains its present value. If expression is a scalar subquery that returns no value, the variable is set to NULL.

For example

DECLARE @u CHAR(12) = '066BDLER'
SELECT  @u  = 'AAAA' WHERE 1 <> 1
SELECT @u

Under any conditions, the value of the SELECT @variable will not change, and DB ENGINE simplifies the statement to

|--Constant Scan

If use RECOMPILE sql build new plan with condition and plan change

        |--Compute Scalar(DEFINE:([Expr1001]='066BDLER    '))
             |--Filter(WHERE:(STARTUP EXPR(NOT '066BDLER    ' like '06%')))
                  |--Constant Scan

But RECOMPILE requires compilation costs, then use CASE for return

ps If you do not change the function, then you can bypass the assignment, otherwise why would you ever APPLY :)

DECLARE @u CHAR(12) = '066BDLER'
SELECT a.user_name, is_v.user_name 
FROM (SELECT @u AS user_name) a
OUTER APPLY [dbo].[vendor_relation_users](a.user_name) AS is_v
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!