Searching for an explanation for a trigger SQL - sql-server

I have the trigger below and am trying to understand what it is supposed to do. I am not a dba but am trying to understand the script below.
Does it mean every time an update (insert, delete, update) happens with the IT01_Incorporates table, the DateUpdated column is updated with the current date?
I actually would like to know, by applying the trigger below, when is the DateUpdated column supposed to be updated? insert, delete and update?
I also would like to understand the meaning of : set nocount on.
Thank you very much
DateUpdated column is datetime type
CREATE trigger [dbo].[TR_IT01_Update]
on [dbo].[IT01_Incorporates]
for update
as
set nocount on
begin
update IT01_Incorporates
set DateUpdated = getdate()
where exists (
select 1 from inserted where incorpuid = IT01_Incorporates.incorpuid
)
end

If you look at the script, you will see in the header lines, the clause for update. This indicates that it is for update only.
To make for inserts and updates, you would have to change it to say for insert, update. You could also add , delete to make it fire on DELETEs as well, but the trigger will not work in that case because there would no longer be any record to UPDATE.

Lets say the following SQL statement was added to a .NET program one year ago:
UPDATE IT01_Incorporates set field1=#Field1, field2=#Field2, Field3=#Field3 where id=#id
Lets say one of your DBA colleagues altered the table yesterday as follows:
ALTER TABLE IT01_Incorporates ADD DateUpdated datetime
Instead of modifying the code; he/she may create a trigger as a temporary measure to ensure that DateUpdated is also updated with every update.

Related

SQL Server Trigger to alter different table

I’m trying to create a trigger to change the value of a column in table B if it finds the information in a column in table A.
An example of my database is below:
[TableA],
itemID
[TableB],
itemID
itemInStock
Once a user creates an entry in Table A declaring an itemID, the trigger needs to change the TableB.itemInStock column to ‘Yes’
I’m still learning SQL so excuse me if I’ve missed something, let me know if you need any more info.
I understand there are better ways of doing this but I've been told I need to do this using a trigger.
I've attempted a few different things, but as it stands nothing is working, below is the current solution I have however this updates all itemInStock rows to 'Yes', where as I only want the ones to update where the TableB.itemID matches the itemID entered in TableA.
ALTER TRIGGER [itemAvailability] ON [dbo].[TableA] FOR
INSERT
AS
BEGIN
UPDATE [dbo].[TableB] set itemInStock = 'Yes' WHERE
TableB.itemID = itemID
END
Two problems -
you're not looking at the Inserted pseudo table which contains the
newly inserted rows
you're assuming the trigger is called once per row - this is not the
case, the trigger is called once per statement and the Inserted
pseudo table will contain multiple rows - and you need to deal with
that
So, your code should look like this -
ALTER TRIGGER [itemAvailability] ON [dbo].[TableA]
FOR INSERT
AS
UPDATE TB
SET itemInStock = 'Yes'
FROM [dbo].[TableB] TB JOIN inserted I
on TB.itemID = I.itemID

SQL Server UPDATE Trigger - breaking things

I have an UPDATE statement that, long story short, runs every half minute. This statement is in Powershell so don't mind the variable syntax...
UPDATE dbo.MobileLeases
SET IPAddress = '$($l.IPAddress)',
OwnerName = '$($l.OwnerName)',
Building = '$($l.Building)',
TimeOn = '$($l.Time)',
LeaseExpiry = '$($l.LeaseExpiry)',
Phone = '$($l.Phone)',
OwnerEmail = '$($l.OwnerEmail)'
WHERE PhysicalAddress = '$($l.DeviceID)';
This part works great and I have no problem updating these columns. It updates multiple rows each time it runs.
I have an update trigger I am trying to put on this table, dbo.MobileLeases. When the Building column is updated in dbo.MobileLeases, I want to perform an INSERT into another table, dbo.LeaseAudit.
The insert into seems to work for the first update after the trigger is in place. After that, the scheduled UPDATE statement (from Powershell) stops working! Which is confusing to me, but here is the trigger...
CREATE TRIGGER [dbo].[trigger_LeaseAudit]
ON [dbo].[MobileLeases]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE (Building)
BEGIN
INSERT INTO dbo.LeaseAudit(PhysicalAddress, DeviceName, OwnerName, Building, TimeOn, IPAddress)
SELECT
i.PhysicalAddress, i.DeviceName, i.OwnerName, i.Building,
i.TimeOn, i.IPAddress
FROM
MobileLeases AS m
INNER JOIN
inserted AS i on m.PhysicalAddress = i.PhysicalAddress
INNER JOIN
deleted AS d on m.PhysicalAddress = d.PhysicalAddress
WHERE
m.Building <> d.Building
END
END
As you can see I am trying to INSERT INTO dbo.LeaseAudit when (Building) is updated on dbo.MobileLeases, WHERE the old update value (d.Building) is different to the new value (m.Building).
I guess my biggest question is how is this trigger breaking the initial update query? With the trigger in place, the scheduled update statement stops working. When I remove the trigger, everything works again.
Thank you for any advice.
The answer is that the UPDATE transaction was failing as a whole.
The update trigger configured on tableA is designed to insert a new row on tableB, when tableA.column1 is updated.
The insert statement includes a column that was set as a PK on tableB. Obviously, the insert statement could not insert a duplicate value in the PK column, so the entire update was bombing.
The solution for me was to remove the PK attribute from tableB.PK. It is an audit table, so I should not miss it.
Thank you

SQL server GetDate in trigger called sequentially has the same value

I have a trigger on a table for insert, delete, update that on the first line gets the current date with GetDate() method.
The trigger will compare the deleted and inserted table to determine what field has been changed and stores in another table the id, datetime and the field changed. This combination must be unique
A stored procedure does an insert and an update sequentially on the table. Sometimes I get a violation of primary key and I suspect that the GetDate() returns the same value.
How can I make the GetDate() return different values in the trigger.
EDIT
Here is the code of the trigger
CREATE TRIGGER dbo.TR
ON table
FOR DELETE, INSERT, UPDATE
AS
BEGIN
SET NoCount ON
DECLARE #dt Datetime
SELECT #dt = GetDate()
insert tableLog (id, date, field, old, new)
select I.id, #dt, 'field', D.field, I.field
from INSERTED I LEFT JOIN DELETED D ON I.id=D.id
where IsNull(I.field, -1) <> IsNull(D.field, -1)
END
and the code of the calls
...
insert into table ( anotherfield)
values (#anotherfield)
if ##rowcount=1 SET #ID=##Identity
...
update table
set field = #field
where Id = #ID
...
Sometimes the GetDate() between the 2 calls (insert and update) takes 7 milliseconds and sometimes it has the same value.
That's not exactly full solution but try using SYSDATETIME instead and of course make sure that target table can store up datetime2 up to microseconds.
Note that you can't force different datetime regardless of precision (unless you will start counting up to ticks) as stuff can just happen at the same time wihthin given precision.
If stretching up to microseconds won't solve the issue on practical level, I think you will have to either redesign this logging schema (perhaps add identity column on top of what you have) or add some dirty trick - like make this insert in try catch block and add like microsecond (nanosecond?) in a loop until you insert successfully. Definitely not s.t. I would recommend.
Look at this answer: SQL Server: intrigued by GETDATE()
If you are inserting multiple ROWS, they will all use the same value of GetDate(), so you can try wrapping it in a UDF to get unique values. But as I said, this is just a guess unless you post the code of your trigger so we can see what you are actually doing?
It sounds like you're trying to create an audit trail - but now you want to forge some of the entries?
I'd suggest instead adding a rowversion column to the table and including that in your uniqueness criteria - either instead of or as well as the datetime value that is being recorded.
In this way, even if two rows are inserted with identical date/time data, you can still tell the actual insertion order.

SQL Server timestamping trigger

My knowledge of SQL is pretty limited as I mostly focus in backend Ruby development. However, due to architectural changes and wanting to keep things well designed; I have decided to set up timestamping on the database level rather than on the backend level.
As it goes right now, all of my tables have two columns: CreatedAt and UpdatedAt, both with a default value of GETDATE().
However, I now need to set up a timestamping trigger for UpdatedAt, so that every time a row (or rows) are updated, the UpdatedAt column for those rows gets a brand new timestamp.
I am having trouble with the following trigger I wrote. I am getting an error:
Incorrect Syntax near '='
I am testing out my trigger on my Orders table first, and then I plan to move the functionality to all tables.
CREATE TRIGGER dbo.trgTimestampAfterUpdate
ON Dbo.Orders
AFTER UPDATE
AS
BEGIN
IF EXISTS (SELECT * FROM inserted)
BEGIN
SET UpdatedAt = GETDATE()
END
END
I know that I can access the inserted, and deleted virtual tables when using a trigger. My thought with this query was that I would use inserted in order to distinguish which rows have been updated. If anyone can help that would be great, and also if you wouldn't mind explaining to me what I messed up with my syntax or line of thinking would be greatly appreciated.
You can't really access the inserted tables quite like that. Having just Set UpdatedAt =... is an incomplete statement. Implicitly it makes sense to you but even in your trigger, you have to make complete SQL statements.
The way to do this is to JOIN to the INSERTED table (in the example below, I'm using a semi-join) You can then use the contents of the INSERTED table to perform another update.
CREATE TRIGGER [dbo].[trgTimestampAfterUpdate] ON dbo.orders
FOR UPDATE
AS
BEGIN
IF NOT(UPDATE(UpdatedAt)) --Avoid triggers firing triggers
BEGIN
UPDATE dbo.orders
SET UpdatedAt = GETDATE()
WHERE id IN ( SELECT id
FROM inserted )
END
END
Two REALLY important things to note in this code example. First Updating the table with the trigger on it will cause the trigger to fire again (creating a loop that will increase until you reach the max level of nested triggers on your system.) I put a check to make sure it terminates if you're only updating the updatedat column.
Second, never ever assume there is only one row in the inserted table. Something like the code below is a very common mistake
DECLARE #id INT
SELECT #id = id FROM INSERTED
UPDATE MyTable
SET UpdatedAT = GETDATE()
WHERE id = #id
--DON'T DO THIS!
This looks right, and is a common mistake, but it will only ever update 1 record and there could be any number of records in the INSERTED table.

Query help to track daily updates made to table(for specific column)

I have 2 tables Individual(IndividualId is primary key) and IndividualAudit. Every time update is made on individual table
record goes to audit table. There are many columns that can be modified but i am interested only in picking up records where SSN is modified.
I m using below query:
Select DI.IndividualId,DI.ssn FRom Individual I
INNER JOIN IndividualAudit A
ON(I.IndividualId = A.IndividualId and A.UpdateDate = GETDATE())
where i.updatedate = GETDATE() and I.ssn <> a.ssn
group by I.IndividualId,I.ssn
Can someone please tell me whether my approach is correct.
Actually i was searching on google and got scared looking at below link:
Query help when using audit table
the person who answered similar query on this post seem to be very good with sql and comparing with his answer my approach looks quite naive.
so i just want to know where am i wrong in my understanding.
Thanks a lot
Rather than fixing the query, I'd suggest instead using an update trigger aimed specifically at changes to that SSN column you're concerned about. The query you've supplied won't work because of the date comparison (as user2159471 has pointed out). But even after you get the query fixed, you'll still have to run it in order to see which SSNs have been updated.
Instead use a SQL update trigger that, perhaps, inserts an entry into a third table each time an individual's SSN get changed. Then you can look at that table any time you, or run a report against it, to see who's been changed.
The trigger code looks like this:
CREATE TRIGGER MyCoolNewTrigger ON Individual
FOR UPDATE
AS
SET NOCOUNT ON
IF (UPDATE(SSN))
BEGIN
Declare #oldSSN as varchar(40)
Declare #NewSSN as varchar(40)
set #oldSSN = deleted.SSN --holds the old SSN being changes
Set #NewSSN = inserted.SSN -- holds the new SSN inserted
Insert into IndividualUpdateLog (NewSSN, OldSSN, ChangeDate)
values (#NewSSN, #oldSSN, getdate)
END

Resources