I have a SQL Server 2008 database that has a Trigger. This trigger is defined as follows:
CREATE TRIGGER [dbo].[Trigger_Car_Insert] ON [dbo].[Car] FOR INSERT
AS
UPDATE
[Lot]
SET
[TotalCars]=lotCars.TotalCars
FROM
[Lot] l JOIN (
SELECT
c.[LotID], COUNT(*) as 'TotalCars'
FROM
inserted i JOIN [Car] c ON i.[LotID]=c.[LotID]
WHERE
c.[IsSold]=0
GROUP BY
c.[LotID]
) lotCars ON l.[ID]=lotCars.[LotID]
This works well for inserting. However, when a car gets sold, the IsSold flag gets updated to true. When this happens, I want a trigger to update the "TotalCars" property on the Lot table. I know there is an "inserted" and "deleted" table to detect what was just inserted/deleted. However, I cannot figure out the equivalent for updating.
How do I do this on SQL Server 2008? Thank you!
There is no "updated table" in update trigger. The values before update statement are in "deleted" table and new values are in "inserted" table. You can check whether a specific column was updated or not by using COLUMNS_UPDATED function.
Here is a simple example: An Introduction to Triggers -- Part II
Related
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
I have a table called dsReplicated.matDB and a column fee_earner. When that column is updated, I want to record two pieces of information:
dsReplicated.matDB.mt_code
dsReplicated.matDB.fee_earner
from the row where fee_earner has been updated.
I've got the basic syntax for doing something when the column is updated but need a hand with the above to get this over the line.
ALTER TRIGGER [dsReplicated].[tr_mfeModified]
ON [dsReplicated].[matdb]
AFTER UPDATE
AS
BEGIN
IF (UPDATE(fee_earner))
BEGIN
print 'Matter fee earner changed to '
END
END
The problem with triggers in SQL server is that they are called one per SQL statement - not once per row. So if your UPDATE statement updates 10 rows, your trigger is called once, and the Inserted and Deleted pseudo tables inside the trigger each contain 10 rows of data.
In order to see if fee_earner has changed, I'd recommend using this approach instead of the UPDATE() function:
ALTER TRIGGER [dsReplicated].[tr_mfeModified]
ON [dsReplicated].[matdb]
AFTER UPDATE
AS
BEGIN
-- I'm just *speculating* here what you want to do with that information - adapt as needed!
INSERT INTO dbo.AuditTable (Id, TriggerTimeStamp, Mt_Code, Old_Fee_Earner, New_Fee_Earner)
SELECT
i.PrimaryKey, SYSDATETIME(), i.Mt_Code, d.fee_earner, i.fee_earner
FROM Inserted i
-- use the two pseudo tables to detect if the column "fee_earner" has
-- changed with the UPDATE operation
INNER JOIN Deleted d ON i.PrimaryKey = d.PrimaryKey
AND d.fee_earner <> i.fee_earner
END
The Deleted pseudo table contains the values before the UPDATE - so that's why I take the d.fee_earner as the value for the Old_Fee_Earner column in the audit table.
The Inserted pseudo table contains the values after the UPDATE - so that's why I take the other values from that Inserted pseudo-table to insert into the audit table.
Note that you really must have an unchangeable primary key in that table in order for this trigger to work. This is a recommended best practice for any data table in SQL Server anyway.
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
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.
Solution required in SQL Server.
Suppose there are 2 tables
TICKET table with following columns:
item_id - PK
ticket_cost
TICKET_PAST with columns:
price - FK
ticket_new_cost
The question is to write a trigger such that whenever a price in the TICKET table is inserted, updated or deleted a new row should be generated by trigger?
Using an after update trigger, and accessing the new value from inserted and the old value from deleted:
create trigger dbo.item_price_update_trigger
on dbo.item
after update as
begin;
set nocount on;
insert into item_hist (item_id, price, new_price)
select i.item_id, d.price, i.price
from inserted i
inner join deleted d
on i.item_id = d.item_id
end;
go
rextester demo: http://rextester.com/PBB85814
This trigger answers your question, but would most likely be just one of three triggers for a complete auditing/history solution. You may want a trigger for after insert to store the initial insert of an item, and an after delete trigger to record the final price of an item that was deleted.
You would also probably want to include the dates of when these actions occurred, so you could query what the effective price was of an item at a given time.
For a somewhat automated option of creating audit/history tables and related triggers, this article and the related scripts may be helpful: Quick And Easy Audit Tables - Dave Britten
Reference:
Use the inserted and deleted Tables
create trigger (Transact-SQL)
DML Triggers