tsql trigger that does not roll back insert - sql-server

I have one table (so called A) in my MS SQL Server database and I created after insert trigger on it that processes the inserted data and inserts some of the columns into another table (let's say B).
So far it works pretty well, but I have a problem when the second insert (triggered) into table B is not proper (ex. inserted values are not in line with integrity constraints). In this case all transactions are rolled back, especially the first insert into table A.
I'd like to have values inserted into table A even if the second insert (into table B) was wrong and was not accomplished. I've tried several versions with TRY/CATCH block but at anytime my trigger throws an error and all transaction is rolled back. Is there any way to work around this issue? Thanks in advance.

Try cleaning the data to satisfy the integrity constraints prior to INSERT to table B (ie - do WHERE EXISTS checks as part of the INSERT)

Related

Can the INSERTED table contain values from two simultaneous transactions that fired the same trigger? SQL Server 2012

I have the same application on different hosts bulk inserting into the same table. Each bulk insert fires a trigger. The structure of the table is as follows:
Hostname Quantity
---------------------
BOX_1 10
BOX_1 15
BOX_1 20
BOX_1 11
If I have the following code as part of the trigger:
DECLARE #hostname VARCHAR(20)
SELECT #hostname = Hostname
FROM INSERTED
Each bulk insert contains only one hostname since the application is only capturing data from the box its running on, but if two machines bulk insert simultaneously into the same table, could the INSERTED table be a combination of bulk inserts from different machines?
Or will the triggers execute sequentially, meaning the INSERTED table will always contain data from only one application at a time?
I need to know if my code setting the #hostname variable has any possibility of not being confined to just one choice.
The INSERTED (and DELETED) table will only ever contain rows from the statement that caused the trigger to fire.
See here: https://msdn.microsoft.com/en-us/library/ms191300(v=sql.110).aspx
The inserted table stores copies of the affected rows during INSERT
and UPDATE statements. During an insert or update transaction, new
rows are added to both the inserted table and the trigger table. The
rows in the inserted table are copies of the new rows in the trigger
table.
The rows in these tables are effectively scoped to the insert/update/delete statement that caused the trigger to fire initially.
See also here for some more info: SQL Server Trigger Isolation / Scope Documentation
But bear in mind in your trigger design that some other insert or update operation (a manual bulk insert, or data maintenance) might cause your trigger to fire, and the assumption about the hostname may no longer hold. Probably this will be years down the line after you've moved on or forgotten about this trigger!

SQL Server - simple discard of duplicate keys/ rows when inserting

I'm feeding data into SQL Server database and 1 out of every 1000 records is a duplicate due to matters outside my control. It's an exact duplicate - the entire record, the unique identifier -- everything.
I know this can solved with an 'updated' rather than insert step ... or 'on error, update' instead of insert, perhaps.
But is there a quick and easy way to make SQL Server ignore these duplicates? I haven't made an index/ unique constraint yet -- but if I did that, I don't want a 'duplicate' key value breaking or interrupting the ETL/ data flow process. I just SQL Server to keep executing the insert query. Is there a way to do this?
Just add a WHERE NOT EXISTS to the statement you're executing -
INSERT INTO table VALUES('123', 'blah') WHERE NOT EXISTS(select top 1 from table where unique_identifier_column = '123')
Just to be clear for anyone else hitting this issue, for the best performance and a slight chance of losing an insert, one should define primary key in the table and use IGNORE_DUP_KEY = ON.
If you're looking for a duplicate record on every field just use the distinct clause in your select:
Insert into DestinationTable
Select Distinct *
From SourceTable
EDIT:
I misinterpreted your question. You're trying to find a low impact way to prevent adding a record that already exists in your DestinationTable.
If you want your inserts to remain fast, one way to do it is to add an identity column to your table as the primary key. Let your duplicate records get added, but then run a maintenance routine on down or slow time that checks all records added since the last check and deletes any added duplicates. Otherwise, there is no easy way... you will have to check on every insert.

SQL Server - How to update only the inserted row of table through trigger?

The problem is I have inserted a new row in a table through procedure which have a AFTER INSERT trigger on it, what I want to do is to update only this new inserted row though trigger, is there any way to do this?
Yes.
Have you tried reading the documentation? I mean, at least once.
THe part where it tells you the trigger has a virtual table (inserted) with all the rows it processes (may be more than one actually, an insert can cover more than one row) and you can then use standard SQL on this (i.e. to find the updated rows in the real table and then update them)?
Your question is the textbook example of a simple standard tutorial trigger chapter 1.
A little google fu - "tsql trigger update inserted table".
Item 1: http://technet.microsoft.com/en-us/library/ms191300.aspx, named "Use the inserted and deleted Tables"
You could also just use search here instead of asking.
SQL Insert trigger to update INSERTED table values

Can executing DDL command e.g alter query affects the rows of the table?

I am trying to execute scenarios when DDL commands affects the number of rows of the table,but executing alter command always return 0 number of rows.
a) Table a has 3 columns b,c,d with 3 records inserted.
b) ALTER TABLE a DROP COLUMN b
Dropping column b shouldn't be affecting the rows already in table.
To speak in simple terms, Except for TRUNCATE , And DROP TABLE no other DDL would affect the data (rows) the table holds..
To speak technically, a DDL is supposed to touch the schema objects and not the data. TRUNCATE will reset the High WaterMark (HWM). And marked as blocks have no data. DROP TABLE will entirely drop the metadata and the data associated with it.
CREATE as SELECT is something oracle gives specially apart from standard SQL, where a DDL (CREATE) is executed first using the result set metadata(FROM SELECT) and then data is loaded too! If the loadimg fails for any reason, the process would be halted and no object creation happens!

how to work with after insert trigger in sql server 2008

i am working on sql server, where i want to insert the record in a particular table say (a), this table contains two column [id (Identity Field) and name(nvarchar(max)] now after the records is inserted in table (a), a trigger should fire and insert the identity field value in table b.... i am using after insert trigger for this purpose but i am not getting how i would be getting the identity field value in trigger... which should be inserted in table b.
This is what i am using
create trigger tri_inserts on (a)
after insert
as
begin
insert into b (id, name) values (?,?)
end
Please reply as soon as possible..
Thanks and Regards
Abbas Electricwala
create trigger tri_inserts on a
after insert
as
set nocount on
insert into b (id, name)
SELECT id, name FROM INSERTED
GO
#gbn has the best solution, but I want you to understand why the SELECT clause is better than using a VALUES clause in a trigger. Triggers fire for each batch of records inserted/updated/deleted. So the inserted pseudotable or the deleted pseudotable may have one record or they may have a million. The trigger has to be able able to handle either case. If you use a values clause, you only get the action happening for one of the records out the the million. This casues data integrity issues. If you decide to loop through the records in a cursor and use the VALUES clause, your performance will be horrible when you get a large number of records. When I came to this job, we had one such trigger, it took 45 minutes to insert a 40,000 record insert. Removing the cursor and using a set-based solution based on athe SELECT clause (Although a much more complex one than the example)reduced the time for the same insert to around 40 seconds.

Resources