SQL Trigger - help with fundamentals - sql

I rarely write triggers. I can use help setting up the thing.
CREATE TRIGGER audit_tableName
ON dbo.tableNameAudit
AFTER CREATE, UPDATE, DELETE on tableName
AS
BEGIN
--Get Created,updated,deletes items
INSERT into dbo.tableNameAudit(columns) VALUES ([allCUDitems])
END
GO
How do I get an iterate any CREATED, UPDATED, DELETED items that caused the trigger?

check out this msdn article.
the short of it are there are 2 special tables, inserted and deleted, that are accessible in your trigger. inserted will contain updated rows and inserted rows, while deleted will contain updated rows and deleted rows.
make sure that you understand that for a batch operation a trigger is only fired one time, so be sure to handle the possibility of multiple rows being present in those tables.

Triggers have access to two pseudo tables: INSERTED and DELETED. As their name suggests, these pseudo tables will contain all the values added or removed from the table. An update will cause a row in each of the pseudo-tables. The structure of these pseudo-tables is identical with the structure of the table on which the table is declared.
In addition the UPDATE() function inside a trigger will return TRUE for columns that were updated.

You can use INSERTED.[COLUMN] OR
SELECT [COLUMN]
FROM INSERTED
This on SQL Server.
Hope it helps.

Related

Get a reference to insert rows with triggers

I'm trying to get a reference to a set of rows that I'm trying to insert into a table through a multiple insert. For example if I execute:
INSERT INTO T VALUES (0,'A'),(1,'B'),(2,'C')
I would like to get a reference in a before insert trigger to a "table" that contains these 3 rows. Is that possible?
And another question: what does a REFERENCING NEW_TABLE represents in a before trigger (maybe could this be the answer to the first question)?
Thanks
According to documentation:
REFERENCING NEW TABLE AS identifier
Specifies a temporary table name which identifies the affected rows as modified by the triggering SQL operation and by any SET
statement in a BEFORE trigger that has already executed.
Also take a look:
FOR EACH STATEMENT
Specifies that the triggered action is to be applied only once for the whole statement. This type of trigger granularity cannot be
specified for a BEFORE trigger or an INSTEAD OF trigger (SQLSTATE
42613). If specified, an UPDATE or DELETE trigger is activated, even
if no rows are affected by the triggering UPDATE or DELETE statement.
maybe it will suite better your needs (of course you need to go with AFTER trigger)

How to create a trigger to delete a record

Looking for ideas on how to write a trigger that will delete a record when a condition is met.
I have some records being written to a SQL Server 2008 database table. These records that are being written are not important and I would like to see them removed. There are two columns that will have unique information when these records are written and I would like a trigger to remove them as soon as they are written.
I could run a daily job to delete all records that equal X and Y but my thought why not delete the records as they are written.
What would this kind of trigger look like?
If you are not able to change that at any app layer you can use an INSTEAD OF INSERT trigger and those rows will not even be inserted at all.
It will save the database from both inserting and deleting.

Keep a shadow copy of a table while retaining records removed from the original

This is probably laughably easy for an SQL expert, but SQL (although I can use it) is not really my thing.
I've got a table in a DB. (Let's call it COMPUTERS)
About 10.000 rows. 25 columns. 1 unique key: Column ASSETS.
Occasionally an external program will delete 1 or more of the rows, but isn't supposed to do that, because we still need to know some info from those rows before we can really delete the items.
We can't control the behavior of the external application so we came up with a different idea:
We want to create a second identical table (COMPUTERS_BACKUP) and initially fill this with a one-on-one copy of COMPUTERS.
After that, once a day copy new records from COMPUTERS to COMPUTERS_BACKUP and update those records in COMPUTERS_BACKUP where the original in COMPUTERS has changed (ASSETS column will never change).
That way we keep the last state of a record deleted from COMPUTERS.
Can someone supply the code for a stored procedure that can be scheduled to run once a day? I can probably figure this out myself, but it would take me several hours or so and I'm very pressed for time.
just create a trigger for insert computers table
CREATE TRIGGER newComputer
ON [Computers]
AFTER INSERT
Begin
INSERT INTO COMPUTERS_BACKUP
SELECT * FROM Inserted
End
It'll work when you insert new computer to computers table and it'll also insert the record to bakcup table
When you update computers you could change computers backup too with update trigger
CREATE TRIGGER newComputer
ON [Computers]
AFTER UPDATE
Begin
//can access before updating the record through SELECT * FROM Deleted
//can access after updating the record through SELECT * FROM Inserted
UPDATE Computers_BACKUP SET
(attributes) = inserted.(attribute)
WHERE id = inserted.id
End
At the end I guess you don't want to delete the backup when original record is deleted from computers table. You can chech more examples from msdn using triggers.
When a record removed from computers table
CREATE TRIGGER computerDeleted ON [Computers] AFTER DELETE
Begin
INSERT INTO Computers_BACKUP
SELECT * FROM Deleted
End
Besides creating triggers, you may look into enabling Change Data Capture, which is available in SQL Server Enterprise Edition. It may be an overshot, but it should be mentioned and you may find it useful for other tables and objects.
IMHO a possible solution, if you never delete records (only update) from that table in your application, can be to introduce an INSTEAD OF DELETE trigger
CREATE TRIGGER tg_computers_delete ON computers
INSTEAD OF DELETE AS
DELETE computers WHERE 1=2;
It will prevent the deletion of the records.
Here is SQLFiddle demo.
A trigger for Before Delete event can help you to guard this table:
CREATE TRIGGER backup_row_before_delete ON COMPUTERS_Table FOR Delete
as
INSERT INTO Computers_Backup
SELECT deleted.* from deleted
You can change deleted.* for deleted.col1, deleted.col2 if you want to keep certain columns only.
will delete 1 or more of the rows, but isn't supposed to do that
Then you have permission and integrity issues.
You can most certainly use a trigger to record deletions (and updates of course) but I would not recommend you use it purely to keep a copy of stuff you didn't want deleted in the first place!
Remove delete permissions if you have to or beef up your data integrity if you can. Without your schema it's hard to tell exactly how though.
Finally, use your (INSTEAD OF) trigger to check whatever conditions you need to prevent the delete when appropriate.

Need a sql statement to do upate and insert at the same time

I need a sql statement, to insert a new row in one database table and update an existing row in another database table based on some conditions.
Is there a way to do this? To insert a row in one table and update a row in another database table in one sql statement?
Thanks in advance!
Yes, they are called Transactions, and are implemented with START TRANSACTION and COMMIT/ROLLBACK with something like:
START TRANSACTION;
INSERT INTO ...
UPDATE table2 SET name='TOTO' WHERE type=1;
COMMIT;
EDIT
This is not in fact one SQL query, but the operation is done atomically - and I think that is what you need.
A single SQL statement allows you to update one table, not several; if that statement is a MERGE then you can specify insert/update/delete actions but still targeting just the same one target table.
If you just want consistency, use transactions; until a transaction is committed, changes within it are not visible to the outside world.
If you want that a single update (which you cannot control) resulted in a coordinated insert, use an on update trigger in the table being updated. The trigger would insert appropriate row(s) into other table(s).
You can use Trigger to update second table on insert of first table
Yes, it's possible with stored procedures.
Watch this: Stored procedures

Multiple rows update trigger

If I have a statement
that updates multiple rows, only the trigger will fire only on the first or last row that is being updated (not sure which one). I need to make a trigger that fires for ALL the records that are being updated into a particular table
Assuming SQL Server, A trigger only fires once per update, regardless of the number of rows that are updated. If you need to carry out some additional logic based on updates to multiple rows you can access the changed records by looking at the INSERTED and DELETED logical tables that are accessible in the context of a trigger.
You have not specified the database .....
In Oracle a trigger can be defined to fire for individual rows and based on the type of transaction:
CREATE OR REPLACE TRIGGER BIUDR_MY_TABLE
BEFORE INSERT OR UPDATE OR DELETE
ON MY_TABLE
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
pk PLS_INTEGER;
BEGIN
etc ....
You just need to indicate if your trigger needs to be executed "FOR EACH ROW" or "FOR EACH STATEMENT". Adding one of these two clauses in the trigger definition will tell the DBMS when to execute the trigger (most, but not all, DBMSs support it). If you don't indicate this clause then the DBMS uses the default option which in your case seems to be the FOR EACH STATEMENT option, and that's why your trigger only fires one for each update sentence, regardless of how many rows you are updating