SQL Trigger not working upon update - sql

I have the following code (in sql server - via 2012): i can't seem to get it right. any suggestions.
Table:
select top 1000 [supplier],
[item],
[reorder_level],
[current_inventory],
[reorder],
from [clinic].[dbo].[emr_suppliers]
I'm working on a trigger and a bit stuck.
CREATE TRIGGER reorder_supplies
ON emr_suppliers
After insert, update
As BEGIN
update emr_suppliers
set reorder = 'yes'
where (emr_suppliers.reorder = emr_suppliers.current_inventory or emr_suppliers.reorder > emr_suppliers.current_inventory)
update emr_suppliers
set reorder = 'no'
where emr_suppliers.reorder < emr_suppliers.current_inventory
END
What the trigger has to do is compare the Current Inventory with the Reorder Level column, and if the value of the Current Inventory is equal to or less than the Reorder Level, it will put a value of Yes in the Reorder column, and if it is not, then it will put a No value instead.

The trigger itself looks syntactically correct.
However, I don't think it's a solution with a decent performance since each and every row of the emr_suppliers table is touched twice, even though there was no data change at all for most of the rows (e.g. after insert of a new row or update of a single value).
I'd use a solution based on the internal inserted table together with a CASE expression:
UPDATE emr_suppliers
SET reorder =
CASE WHEN emr_suppliers.reorder < emr_suppliers.current_inventory THEN 'no'
WHEN emr_suppliers.reorder >= emr_suppliers.current_inventory THEN 'yes'
ELSE reorder -- don't change the value
END
FROM emr_suppliers INNER JOIN inserted ON emr_suppliers.primary_key = inserted.primary_key

Related

SQL Server : make update trigger don't activate with no changing value

I want to track the update changes in a table via a trigger:
CREATE TABLE dbo.TrackTable(...columns same as target table)
GO
CREATE TRIGGER dboTrackTable
ON dbo.TargetTable
AFTER UPDATE
AS
INSERT INTO dbo.TrackTable (...columns)
SELECT (...columns)
FROM Inserted
However in real production some of the update queries select rows with vague conditions and update them all regardless of whether they are actually changed, like
UPDATE Targettable
SET customer_type = 'VIP'
WHERE 1 = 1
--or is_obsolete = 0 or register_date < '20160101' something
But due to table size and to analyze, I only want to choose those actually modified data for tracking. How to achieve this goal?
My track table has many columns (so I do not prefer checking inserted and deleted column one by one) but it seldom changes structure.
I guess the following code will be useful.
CREATE TABLE dbo.TrackTable(...columns same as target table)
GO
CREATE TRIGGER dboTrackTable
ON dbo.TargetTable
AFTER UPDATE
AS
INSERT INTO dbo.TrackTable (...columns)
SELECT *
FROM Inserted
EXCEPT
SELECT *
FROM Deleted
I realize this post is a couple months old now, but for anyone looking for a well-rounded answer:
To exit the trigger if no rows were affected on SQL Server 2016 and up, Microsoft recommends using the built-in ROWCOUNT_BIG() function in the Optimizing DML Triggers section of the Create Trigger documentation.
Usage:
IF ROWCOUNT_BIG() = 0
RETURN;
To ensure you are excluding rows that were not changed, you'll need to do a compare of the inserted and deleted tables inside the trigger. Taking your example code:
INSERT INTO dbo.TrackTable (...columns)
SELECT (...columns)
FROM Inserted i
INNER JOIN deleted d
ON d.[SomePrimaryKeyCol]=i.[SomePrimaryKeyCol] AND
i.customer_type<>d.customer_type
Microsoft documentation and w3schools are great resources for learning how to leverage various types of queries and trigger best practices.
Prevent trigger from doing anything if no rows changed.
Writing-triggers-the-right-way
CREATE TRIGGER the_trigger on dbo.Data
after update
as
begin
if ##ROWCOUNT = 0
return
set nocount on
/* Some Code Here */
end
Get a list of rows that changed:
CREATE TRIGGER the_trigger on dbo.data
AFTER UPDATE
AS
SELECT * from inserted
Previous stack overflow on triggers
#anna - as per #Oded's answer, when an update is performed, the rows are in the deleted table with the old information, and the inserted table with the new information –

About Ms Sql Trigger

I want to make a trigger to change the values of BarcodeFormat column.
So I made a trigger, but I am not sure if it works.
Here is the code:
CREATE trigger tr_changedUPC
on Item
after update
as update Item
SET BarcodeFormat=(case when(ISNUMERIC(ItemLookupCode)=1) AND
(LEN(ItemLookupCode)=12) AND (NOT(BarcodeFormat=9)) then 9 else 6 end) from inserted
As you can see, I am making a trigger on item Table. When the value of column Item.ItemLookupCode changes, I want to change the value of column Item.BarcodeFormat, too.
I didn't execute this SQL code yet. So I want you to see this code if it is good.
According to this SQL Fiddle,
CREATE trigger tr_changedUPC
on Item
after update
as update Item
SET BarcodeFormat=(case when(ISNUMERIC(ItemLookupCode)=1) AND
(LEN(ItemLookupCode)=12) AND (NOT(BarcodeFormat=9)) then 9 else 6 end) from inserted
your code should be a little improved in this way, to make columns less ambiguous:
CREATE TRIGGER tr_changedUPC
on Item
after UPDATE
as UPDATE Item
SET Item.BarcodeFormat=(case when(ISNUMERIC(Item.ItemLookupCode)=1) AND
(LEN(Item.ItemLookupCode)=12) AND (NOT(Item.BarcodeFormat=9)) then 9 else 6 end) from inserted;
Your code is fine, according to the results of the fiddle, because the values of column 'BarCodeFormat' are updated accordingly with the update of column 'ItemLookupCode'.

Update a table and return both the old and new values

Im writing a VB app that is scrubbing some data inside a DB2 database. In a few tables i want to update entire columns. For example an account number column. I am changing all account numbers to start at 1, and increment as I go down the list. Id like to be able to return both the old account number, and the new one so I can generate some kind of report I can reference so I dont lose the original values. Im updating columns as so:
DECLARE #accntnum INT
SET #accntnum = 0
UPDATE accounts
SET #accntnum = accntnum = #accntnum + 1
GO
Is there a way for me to return both the original accntnum and the new one in one table?
DB2 has a really nifty feature where you can select data from a "data change statement". This was tested on DB2 for Linux/Unix/Windows, but I think that it should also work on at least DB2 for z/OS.
For your numbering, you might considering creating a sequence, as well. Then your update would be something like:
CREATE SEQUENCE acct_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
CACHE 24
;
SELECT accntnum AS new_acct, old_acct
FROM FINAL TABLE (
UPDATE accounts INCLUDE(old_acct INT)
SET accntnum = NEXT VALUE FOR acct_seq, old_acct = accntnum
)
ORDER BY old_acct;
The INCLUDE part creates a new column in the resulting table with the name and the data type specified, and then you can set the value in the update statement as you would any other field.
A possible solution is to add an additional column (let's call it oldaccntnum) and assign old values to that column as you do your update.
Then drop it when you no longer need it.
Here's what I'd do:
-- create a new table to track the changes.
- with columns identifying a unique key, old-vale, new-value, timestamp
-- create a trigger on the accounts table
to write the old and new values to the new table.
But, not knowing all the conditions, it may not be worth the trouble.

SQL Server insert trigger not working

This is my first time using triggers.
My trigger is not being triggered please help.
CREATE TRIGGER sbhack_autoban
ON LOG_CONNECT201211
FOR INSERT
AS
BEGIN
/* query to run if single or multiple data is
inserted into LOG_CONNECT201211 table */
UPDATE login.dbo.USER_CHECK_LOGIN
SET login.dbo.USER_CHECK_LOGIN.CHECKLOGIN = 2
WHERE login.dbo.USER_CHECK_LOGIN.USER_KEY IN
(SELECT e.USER_KEY
FROM game.dbo.CHAR_DATA0 AS e
INNER JOIN gamelogs.dbo.LOG_USING_DEPOT201211 AS p
ON e.CHAR_KEY = p.CHAR_KEY
WHERE p.GATENUM = 150)
AND login.dbo.USER_CHECK_LOGIN.CHECKLOGIN = 0
AND login.dbo.USER_CHECK_LOGIN.USER_KEY != 51;
END
This is suppose to run the query inside the BEGIN : END if an entry is inserted into the LOG_CONNECT201211 table. But nothing is happening even when I have inserted multiple data into LOG_CONNECT201211.
When your INSERT trigger fires - then at least one new row has been inserted! That's a fact.
Now the question is: given that a single or multiple new rows have been inserted - what do you want to do with this knowledge??
Typically, you could e.g. set a column to a value you cannot specify as a default constraint - or you could insert the fact that the row has been inserted into an audit table or something....
So you'd have something like this:
CREATE TRIGGER sbhack_autoban
ON LOG_CONNECT201211
FOR INSERT
AS
INSERT INTO LogAudit(InsertedDate, UserKey)
SELECT
GETDATE(), i.User_Key
FROM
Inserted i
or something like that....
Update: ok, so you want to run that UPDATE statement when the rows have been inserted - not 100% clear, what columns/values from the inserted rows you want to use - looks like the e.UserKey column only - correct?
Then the UPDATE would be:
UPDATE login.dbo.USER_CHECK_LOGIN
SET login.dbo.USER_CHECK_LOGIN.CHECKLOGIN = 2
WHERE
login.dbo.USER_CHECK_LOGIN.USER_KEY IN
(SELECT USER_KEY FROM Inserted)
AND login.dbo.USER_CHECK_LOGIN.CHECKLOGIN = 0
AND login.dbo.USER_CHECK_LOGIN.USER_KEY != 51;
Update #2:
The point I still don't understand is : why do you want to run an update that uses the USER_CHECK_LOGIN, CHAR_DATA0 and LOG_USING_DEPOT201211 tables, when some rows are getting inserted into a totally separate, unrelated table LOG_CONNECT201211 ??
A trigger is used when you want to do something because rows have been inserted into that table - but in that case, you typically want to do something with the rows and their values that have been inserted...
I just don't see any connection between the rows being inserted into LOG_CONNECT201211 event, and the tables you are then querying from and updating. Where's the link?? WHY do you need to run *this UPDATE when data is inserted into LOG_CONNECT201211 ?? It would make sense if data where inserted into one of the tables involved in the UPDATE - but like this, it just totally doesn't make any sense .....

SQL Trigger 1 row at a time

I'm creating an update trigger that goes like this (SQL Server 2005):
Is the state column of the row is 23 or 25 don't update it. Else update it. It's very simple. I'm trying
OldState = (Select State from Deleted)
If OldState in (25,23)
Update it --how to do it easily?
else
dont do nothing for this row
The problem is that the trigger is called with all the updated rows, so deleted is a set, that means the first instruction won't work because it's trying to get only 1 value and it gets a set..
It's something so simple, am I missing something?
Thank you very much
This code assumes:
the key stays the same to link "old" and "new" rows
you need simple post-update processing
Example:
UPDATE
M --yes, this is correct
SET
SomeCol = SomeValue,
...
FROM
MyTable M
JOIN
DELETED D ON M.KeyCol = D.KeyCol
WHERE
D.State IN (23, 25)