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)
Related
I have this table:
When I make a delete of a box in this table, I need to make an increment of all the following rows.
For example: if I delete BoxNo '4' then the rows which are after the last row of BoxNo '4' (5,6,7,..etc) have to make an increment by 1 and be like (4,5,6,...etc.). I hope I succeed in explaining the problem.
Could you please kindly help me to perform this with an SQL Server query?
Thanks in advance.
Executing actions automatically after rows are deleted is what TRIGGERS are for.
In your case, it looks something like:
CREATE TRIGGER MyTable_AfterDelete
ON MyTable
FOR DELETE
AS
update MyTable set RowCounter = RowCounter + 1
from deleted
inner join MyTable on MyTable.BoxNo > deleted.BoxNo
GO
As you can see SQL Server doesn't raise a trigger after each row deleted but after each DELETE statement execution, which can involve several rows deleted, so we need to use the "deleted" pseudo-table to apply our action on every one of those rows deleted.
PS: This is how what you asked can be done, although I agree with the comments that say that you could structure better this problem instead of needing to update so many rows after every delete.
UPDATE
If you want to execute it manually on every delete instruction, instead of automatically on a trigger, you can pass a parameter to your DELETE statement on C# in order to update the posterior RowCounters. Something like:
delete from MyTable where BoxNo = #BoxNo
update MyTable set RowCounter = RowCounter + 1 where BoxNo > #BoxNo
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
I have a list of items that I need to update based on their unique ID in a SQL Server 2005 environment. I was wondering what the best way of writing a script to update these items.
I know I can simply update a column by writing multiple queries such as:
UPDATE myTable
SET HelpLink = 'newLink'
WHERE ID = 5
UPDATE myTable
SET HelpLink = 'newLink2'
WHERE ID = 6
Is there any other way of doing this without having to repeat the above update about 20 times? Repeating the above tends to make a pretty ugly update script.
NOTE: I have a bulk set of items that I will be updating by their unique ID, these items are not coming from a database table.
I found out that you can use case statements which seems to simplify things quite a bit. This allows me to add multiple items into a single query.
UPDATE [MyTable]
SET HelpLink = CASE ID
WHEN 2 THEN 'MKSDefectsChart.png'
WHEN 6 THEN 'EPMRisks.png'
WHEN 7 THEN 'DCTSHardwareChanges.png'
ELSE NULL
END
WHERE ID IN (2, 6, 7)
You can always update from another table like
update myTable
set HelpLink = myOtherTable.HelpLink
from myOtherTable
where myTable.[ID] = myOtherTable.[ID]
You'll have to create that other table though
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 .....
I am trying to figure out which i need to use here: deleted, inserted or updated.
basically.
I need to write some data to the history table, when the main table is updated, and only if the status changes from something to either pending or active.
This is what I have now:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE AS
DECLARE #statusOldValue char(1)
DECLARE #statusNewValue char(1)
SELECT #statusOldValue = statusCode FROM deleted
SELECT #statusNewValue= statusCode FROM updated
IF (#statusOldValue <> #statusNewValue) AND
(#statusOldValue = 'P' or #statusOldValue = 'A')
BEGIN TRY
INSERT * INTO tblHistoryTable)
select * from [DELETED]
so I want the new data to stay in the main table, the the history table to be updated with what is being overwritten... right now it just copies the same info over. so after update, both my tables have the same data.
There are only the Inserted and Deleted pseudo tables - there's no Updated.
For an UPDATE, Inserted contains the new values (after the update) while Deleted contains the old values before the update.
Also be aware that the triggers is fired once per batch - not once for each row. So both pseudo tables will potentially contain multiple rows! Don't just assume a single row and assign this to a variable - this
SELECT #statusOldValue = statusCode FROM deleted
SELECT #statusNewValue= statusCode FROM updated
will fail if you have multiple rows ! You need to write your triggers in such a fashion that they work with multiple rows in Inserted and Deleted !
Update: yes - there IS a much better way to write this:
ALTER TRIGGER [dbo].[trg_SourceHistory] ON [dbo].[tblSource]
FOR UPDATE
AS
INSERT INTO dbo.tblHistoryTable(Col1, Col2, Col3, ...., ColN)
SELECT Col1, COl2, Col3, ..... ColN
FROM Deleted d
INNER JOIN Inserted i ON i.PrimaryKey = d.PrimaryKey
WHERE i.statusCode <> d.statusCode
AND d.statusCode IN ('A', 'P')
Basically:
explicitly specify the columns you want to insert - both in the INSERT statement as well as the SELECT statement retrieving the data to insert - to avoid any nasty surprises
create an INNER JOIN between Inserted and Deleted pseudo-tables to get all rows that were updated
specify all other conditions (different status codes etc.) in the WHERE clause of the SELECT
This solution works for batches of rows being updated - it won't fail on a multi-row update....
You need to use both the inserted and deleted tables together to check for records that:
1. Already existed (to check it's not an insert)
2. Still exists (to check it's not a delete)
3. The Status field changed
You also need to make sure you do that in a set based approach, as per marc_s's answer, triggers are not single record processes.
INSERT INTO
tblHistoryTable
SELECT
deleted.*
FROM
inserted
INNER JOIN
deleted
ON inserted.PrimaryKey = deleted.PrimaryKey
WHERE
inserted.StatusCode <> deleted.StatusCode
AND (inserted.StatusCode = 'P' OR inserted.StatusCode = 'A')
inserted = the new values
deleted = the old values
There is no updated table, you are looking for inserted.