简体   繁体   中英

Avoid calling a scalar function multiple times in a MERGE and UPDATE statement

I want to call function that return scalar multiple times. How can I do that in a MERGE statement?

My code:

MERGE [dbo].MyTable m
USING (select * from Table2 edbl 
where IsRowError = 0) edbTable
on  edbTable.Filed1 = m.Filed1
WHEN MATCHED THEN UPDATE SET 
m.Filed2 = case when dbo.func1(edbTable.Filed7) = 1 then 1 
                when dbo.func1(edbTable.Filed7) = 0 then 1
                else 0 end,
m.Filed3 = case when dbo.func1(edbTable.Filed7) = 0 then 0 end,
m.Filed4 = case when dbo.func1(edbTable.Filed7) = 0 then 3 end,
m.Filed5 = case when dbo.func1(edbTable.Filed7) = 0 then 9 else 5 end,
m.Filed6 = getdate();

I want also to do it in UPDATE statement:

UPDATE md
set Filed1 = case when dbo.func1(edbl.Filed7) = 0  then 0 end,
    Filed5 = case when dbo.func1(edbTable.Filed7)=0 then 9 else 5 end,
    Filed6 = getdate()
from  Table2 edbl
    join Table3 m on edbl.Filed2= m.Filed2
    join Table4 md on m.Filed3=md.Filed3
    join Table5 mb on md.Filed4 = mb.Filed4
where IsRowError = 0

You can do it in the subquery:

MERGE [dbo].MyTable m
USING (select edbl.*, dbo.func1(edbTable.Filed7) as func1
       from Table2 edbl 
       where IsRowError = 0
      ) edbTable
      on  edbTable.Filed1 = m.Filed1
WHEN MATCHED THEN UPDATE SET 
    m.Filed2 = (case when func1 = 1 then 1 
                     when func1 = 0 then 1
                     else 0
                end),
    m.Filed3 = case when func1 = 0 then 0 end,
    m.Filed4 = case when func1 = 0 then 3 end,
    m.Filed5 = case when func1 = 0 then 9 else 5 end,
    m.Filed6 = getdate();

However, it is not clear that this is a big win. If most rows do not match, this might not be a big improvement.

You could do it once inside USING part:

MERGE [dbo].MyTable m
USING (select *, dbo.func1(Filed7) AS f from Table2 edbl 
where IsRowError = 0) edbTable
on  edbTable.Filed1 = m.Filed1
WHEN MATCHED THEN UPDATE SET 
m.Filed2 = case when f = 1 then 1 
                when f = 0 then 1
                else 0 end,
m.Filed3 = case when f = 0 then 0 end,
m.Filed4 = case when f = 0 then 3 end,
m.Filed5 = case when f = 0 then 9 else 5 end,
m.Filed6 = getdate();

You can use APPLY with UPDATE statement :

UPDATE md
     SET Filed1 = CASE WHEN fun = 0 THEN 0 END,
         Filed5 = CASE WHEN fun = 0 THEN 9 ELSE 5 END,
         Filed6 = getdate()
FROM Table2 edbl JOIN 
     Table3 m 
     ON edbl.Filed2 = m.Filed2 JOIN 
     Table4 md 
     ON m.Filed3 = md.Filed3 JOIN 
     Table5 mb 
     ON md.Filed4 = mb.Filed4 CROSS APPLY
     ( VALUES (dbo.func1(edbl.Filed7)) 
     ) edbl1(fun) 
where IsRowError = 0;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM