Avatar of Cobra967
Cobra967
Flag for United States of America asked on

Help in fine tune my SQL Server trigger.

Hello I need help in fine tune my SQL Server trigger. I need this trigger to execute *ONLY* when the *PhoneNumber* is updated from nothing (NULL) to something and from something to something else (If updating from something to nothing (NULL) then it will not execute.  In shot, the trigger will copy most of the data from table [DATA] record into Table [FOLLOWUP] if the phone number has been added or changed in table [DATA] Thank you.

USE [prd_customers]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[SetFollowUp]
 ON [dbo].[DATA]
 AFTER UPDATE
 AS
 SET NOCOUNT ON;
 INSERT INTO dbo.FOLLOWUP ( 
     RecordIdFK, 
	 FullName, 
	 Address, 
	 City, 
	 State, 
	 Zip, 
	 PhoneNumber, 
	 eMail, 
	 Notes)
 SELECT
	 i.RecordId,
	 i.FullName, 
	 i.Address, 
	 i.City, 
	 i.State, 
	 i.Zip, 
	 i.PhoneNumber, 
	 i.eMail, 
	 i.Notes 
 FROM inserted i
 WHERE PhoneNumber is not null

Open in new window

Microsoft SQL Server

Avatar of undefined
Last Comment
Vitor Montalvão

8/22/2022 - Mon
Vitor Montalvão

Your code looks ok to me.
Why do you think isn't working?
lcohan

--Would be something like:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[SetFollowUp]
 ON [dbo].[DATA]
 AFTER UPDATE
 AS
 SET NOCOUNT ON;

IF UPDATE(PhoneNumber) AND
(  
    -- from not null to null
((SELECT PhoneNumber FROM inserted) is null AND (SELECT PhoneNumber FROM deleted) is null)
OR  -- from null to not null
((SELECT PhoneNumber FROM inserted) is not null AND (SELECT PhoneNumber FROM deleted) is null)
)

BEGIN
 INSERT INTO dbo.FOLLOWUP (
     RecordIdFK,
       FullName,
       Address,
       City,
       State,
       Zip,
       PhoneNumber,
       eMail,
       Notes)
 SELECT
       i.RecordId,
       i.FullName,
       i.Address,
       i.City,
       i.State,
       i.Zip,
       i.PhoneNumber,
       i.eMail,
       i.Notes
 FROM inserted i
 WHERE PhoneNumber is not null
 
END
Cobra967

ASKER
As is the trigger appears to update even when some other field is updated (But I have to confirm this - Only I see are duplicated of the same record in FOLLOUP. It is also possible that when user click the save button from the app, the app may overwrite the PhoneNumber again even though is the same as before, So, is this is the case then the trigger should execute only if the PhoneNumber being updated is different than the original (oldvalue?).
Your help has saved me hundreds of hours of internet surfing.
fblack61
Zberteoc

Use this:
USE [prd_customers]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[SetFollowUp]
 ON [dbo].[DATA]
 AFTER UPDATE
 AS
 SET NOCOUNT ON;
 INSERT INTO dbo.FOLLOWUP ( 
     RecordIdFK, 
	 FullName, 
	 Address, 
	 City, 
	 State, 
	 Zip, 
	 PhoneNumber, 
	 eMail, 
	 Notes)
 SELECT
	 i.RecordId,
	 i.FullName, 
	 i.Address, 
	 i.City, 
	 i.State, 
	 i.Zip, 
	 i.PhoneNumber, 
	 i.eMail, 
	 i.Notes 
 FROM inserted i
 WHERE PhoneNumber is not null
 and i.PhoneNumber in 
 (select PhoneNumber from inserted
  except
  select PhoneNumber from deleted)

Open in new window

lcohan

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[SetFollowUp]
 ON [dbo].[DATA]
 AFTER UPDATE
 AS
 SET NOCOUNT ON;

IF UPDATE(PhoneNumber)
AND
--restrict any updates with same value
((SELECT PhoneNumber FROM inserted) <> (SELECT PhoneNumber FROM deleted))
AND
(  
      -- from not null to null
      ((SELECT PhoneNumber FROM inserted) is null AND (SELECT PhoneNumber FROM deleted) is null)
      OR  
      -- from null to not null
      ((SELECT PhoneNumber FROM inserted) is not null AND (SELECT PhoneNumber FROM deleted) is null)
)
BEGIN

 INSERT INTO dbo.FOLLOWUP (
     RecordIdFK,
       FullName,
       Address,
       City,
       State,
       Zip,
       PhoneNumber,
       eMail,
       Notes)
 SELECT
       i.RecordId,
       i.FullName,
       i.Address,
       i.City,
       i.State,
       i.Zip,
       i.PhoneNumber,
       i.eMail,
       i.Notes
 FROM inserted i
 WHERE PhoneNumber is not null
 
END
Scott Pletcher

USE [prd_customers]
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[SetFollowUp]
ON [dbo].[DATA]
AFTER UPDATE
AS
SET NOCOUNT ON;
INSERT INTO dbo.FOLLOWUP (
      RecordIdFK,
      FullName,
      Address,
      City,
      State,
      Zip,
      PhoneNumber,
      eMail,
      Notes)
SELECT
      i.RecordId,
      i.FullName,
      i.Address,
      i.City,
      i.State,
      i.Zip,
      i.PhoneNumber,
      i.eMail,
      i.Notes
FROM inserted i
INNER JOIN deleted d ON d.RecordId = i.RecordId
WHERE (d.PhoneNumber IS NULL AND i.PhoneNumber IS NOT NULL) OR
    (d.PhoneNumber <> i.PhoneNumber)
GO /*end of trigger*/
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
lcohan

As far as I'm aware the truth is that IF you don't use the

IF UPDATE(col_name) ...

structure in a trigger that trigger will fire and action done regardless which is a waste right? especially if "nothing" needs to get logged/audited/queued and I learned that the hard way with some hefty UPDATE trigger action on a huge Clients table that took massive bulk updates (by merchantid).

"UPDATE() is used anywhere inside the body of a Transact-SQL INSERT or UPDATE trigger to test whether the trigger should execute certain actions."
https://msdn.microsoft.com/en-us/library/ms187326.aspx
Zberteoc

If you have a table with tens of columns to wrap all or lot of them in UPDATE and build a condition it is kind of tedious. It is way simpler and as fast if not faster to use EXCEPT between INSERTED and DELETED tables with a list of columns you are interested in. Also the UPDATE will "fire" even if you put the same value in a column, which is not really an update, while selecting with excepts will filter out the rows with same values updated.
ASKER CERTIFIED SOLUTION
Scott Pletcher

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Cobra967

ASKER
Thank you everyone for the overwhelming contribution to my question! I did not have the to try everyone's suggestion but Scott's code seem to work just fine. Thank you all!
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
Zberteoc

You should start trying the suggestions in the order they are posted. That would be fair.
Cobra967

ASKER
I can certainly see your point, I will do better next time! I am not as experienced as you guys are and I have hard time to pick the "best" solution. For sure you guys have pointed out items that I did not even think about in interest of performance and logic.
Scott Pletcher

Certainly consider solutions in order.  But you should consider accuracy and completeness as well.

For example, technically this method of checking for a changed number is not correct:

FROM inserted i
 WHERE PhoneNumber is not null
and i.PhoneNumber in
 (select PhoneNumber from inserted
  except
  select PhoneNumber from deleted)


Say, for example, Person 1's number changed from 111 to 222.  Person 2's number changed from 333 to 111.  In that situation, phone number 111 would be excluded from the results because of the EXCEPT [ I think; I find that logic somewhat complex to follow], but it shouldn't be, since Person 2's number did change to 111.  

Not likely to happen?  Probably true.  But I think it's possible that two phone numbers could get transposed while being entered, and later someone goes back in to correct them both.  Since it's so rare, the bug could show up years from now instead of during testing, which could be even worse, since it's hard to track down.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Zberteoc

Correct. This should do it then:
USE [prd_customers]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER [dbo].[SetFollowUp]
 ON [dbo].[DATA]
 AFTER UPDATE
 AS
 SET NOCOUNT ON;
 INSERT INTO dbo.FOLLOWUP ( 
     RecordIdFK, 
	 FullName, 
	 Address, 
	 City, 
	 State, 
	 Zip, 
	 PhoneNumber, 
	 eMail, 
	 Notes)
 SELECT
	 i.RecordId,
	 i.FullName, 
	 i.Address, 
	 i.City, 
	 i.State, 
	 i.Zip, 
	 i.PhoneNumber, 
	 i.eMail, 
	 i.Notes 
 FROM inserted i
 inner join 
 (select RecordId,PhoneNumber from inserted
  except
  select RecordId,PhoneNumber from deleted) changed
	on changed.RecordId=i.RecordId
	and changed.PhoneNumber=i.PhoneNumber
WHERE i.PhoneNumber is not null

Open in new window

However, generally speaking the asker SHOULD test the solutions in the order they are offered.
Cobra967

ASKER
To my defense, it is unrealistic to expect users to test possibly dozens of proposals when the response is *overwhelming*. I don't know what your experience is on this subject, however it is my experience that, normally, the last response is the best one since no improvements or refinements are possible. Sure, the first options "could" possible work, but it may not necessarily be the best one like has been pointed out in this very constructive conversation. As for the rating, I am not sure why that is very important to you. Do you get pay accordingly? From my point of view, the Best solution is a simple mechanizing to tell everyone with similar circumstances what did work and what I overall felt was the most effective solution in terms of performance and logic and functionality. I know there is endless way to do things, Normally I am not a fan or very lengthy and convoluted solutions when I a simple and as effective exist. So, how many points everyone should deserve in your opinion? What ultimately is the best solution? Do you all agree?
Zberteoc

That is not the case. If what you said were true then only the experts that post the last would be rewarded points. There are questions with multiple solution given and in that case you don't start to test only the last one because if it works and given points would be totally disrespectful for the time spent by the other experts experts with the result that they will either stop posting or will wait like on eBay to be the last to bid!

You HAVE to test the solutions in order they are given and the first one that works for your problem should be awarded. Scott also is right when he says that in the case of multiple solutions it is recommendable to go over all of them to see which one is more complete and offer best performance if possible. You can also split the points if you consider that all of them are good as alternative solutions.

Anyway, testing only the last and awarding only that with points is against the EE philosophy.
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Vitor Montalvão

normally, the last response is the best one since no improvements or refinements are possible.
Not true at all. Just go and check random closed questions and see how many of them have the last comment marked as solution.
Besides, all Experts here are not paid. They come here because they like to help others and the minimum that an asker can do is to consider their comments by giving them a feedback or in the future they might not want to help you anymore.
Cheers