SQL SERVER - 在WHERE子句中设置变量

时间:2017-01-25 08:54:21

标签: sql-server sql-server-2008 sql-server-2008-r2 sql-update

我正在执行以下更新:

UPDATE MyTable
SET    Field1 = 0       
FROM   MyTable INNER JOIN AnotherTable
       ON MyTable.ID = AnotherTable.ID
WHERE  0=MyFunc(MyTable.ID)

MyFunc是一个返回int值的函数。

但是现在我正在尝试使用MyFunc返回的值来更新表MyTable上的另一个字段。

UPDATE MyTable
SET    Field1 = 0,
       Field2 = CASE WHEN MyFunc(MyTable.ID) = 0 THEN 'OK' ELSE 'NOK' END
FROM   MyTable INNER JOIN AnotherTable
       ON MyTable.ID = AnotherTable.ID
WHERE  0=MyFunc(MyTable.ID)

这里的问题是我调用两次函数MyFunc,一个在SET中,一个在WHERE子句中,然后我担心性能。

我想知道是否有其他方法可以做到这一点。我曾经想过使用变量,我的意思是,在WHERE子句中设置这个变量,然后在更新集中使用它,但我想这是不可能的,对吗?

那么我怎样才能获得更好的数据库性能呢?

1 个答案:

答案 0 :(得分:2)

您可以使用CROSS APPLY来模拟变量。以下SELECT将能够使用变量名称 FuncResult来解决函数的结果。

SELECT MyTable.Field1 
      ,MyTable.Field2
      ,x.FuncResult
FROM  MyTable 
CROSS APPLY(SELECT dbo.MyFunc(MyTable.ID) AS FuncResult) AS x
INNER JOIN AnotherTable
       ON MyTable.ID = AnotherTable.ID
WHERE FuncResult=0

此外,您可以像这里一样检查可更新的CTE:

WITH UpdateableCTE AS
(
    SELECT MyTable.Field1 
          ,MyTable.Field2
          ,x.FuncResult
    FROM  MyTable 
    CROSS APPLY(SELECT dbo.MyFunc(MyTable.ID) AS FuncResult) AS x
    INNER JOIN AnotherTable
           ON MyTable.ID = AnotherTable.ID
    WHERE FuncResult=0
)
UPDATE UpdateableCTE
SET Field1=0
   ,Field2=CASE WHEN FuncResult = 0 /*senseless, as your where clause filters to only this value!*/ THEN 'OK' ELSE 'NOK' END

但是 - 说实话 - 整个问题看起来像开始在二楼建一座房子 ......我很确定,引擎足够聪明,可以破坏一个函数的结果并使用相同的输入重复使用它(至少每行)。

如果你真的打扰性能避免标量函数。如果你需要一个函数, 内联 表值函数,它可能只返回一行中的列,速度要快得多。

更新

此处为INLINED tabe value function(单一陈述, ad-hoc ,无BEGIN...END)的示例:

CREATE FUNCTION dbo.TestInlineTVF(@input INT)
RETURNS TABLE
AS
RETURN SELECT @input*2 AS FuncResult;
GO

DECLARE @tbl TABLE(ID INT IDENTITY,SomeValue VARCHAR(100));
INSERT INTO @tbl VALUES('Row 1'),('Row 2');

SELECT *
FROM @tbl AS t
CROSS APPLY dbo.TestInlineTVF(t.ID) AS x
GO
DROP FUNCTION dbo.TestInlineTVF;