multithreading with the trigger - sql

I have written a Trigger which is transferring a record from a table members_new to members_old. The Function of trigger is to insert a record into members_old on after insert in members_new. So suppose a record is getting inserted into a members_new like
nMmbID nMmbName nMmbAdd
1 Abhi Bangalore
This record will get inserted into members_old with the same data structure of the table
My trigger is like :
create trigger add_new_record
after
insert on members_new
for each row
INSERT INTO `test`.`members_old`
(
`nMmbID`,
`nMmbName`,
`nMmbAdd`
)
(
SELECT
`members_new`.`nMmbID`,
`members_new`.`nMmbName`,
`members_new`.`nMmbAdd`
FROM `test`.`members_new`
where nMmbID = (select max(nMmbID) from `test`.`members_new` // written to read the last record from the members_new and stop duplication on the members_old , also this will reduce the chances of any error . )
)
This trigger is working for now , but my confusion is that what will happen if a multiple insertion is happening at one instance of time.
Will it reduce the performance?
Will I face deadlock condition ever in any case as my members_old have FKs?
If any better solution for this situation is there, please give limelight on that

From the manual:
You can refer to columns in the subject table (the table associated with the trigger) by using the aliases OLD and NEW. OLD.col_name refers to a column of an existing row before it is updated or deleted. NEW.col_name refers to the column of a new row to be inserted or an existing row after it is updated.
create trigger add_new_record
after
insert on members_new
for each row
INSERT INTO `test`.`members_old`
SET
`nMmbID` = NEW.nMmbID,
`nMmbName` = NEW.nMmbName,
`nMmbAdd` = NEW.nMmbAdd;
And you will have no problem with deadlocks or whatever. Also it should be much faster, because you don't have to read the max value before (which is also unsecure and might lead to compromised data). Read about isolation levels and transactions if you're interested why...

Related

Edit inserted table sql

When insert I need edit a value if it is null. I create a trigger but I don't know how to edit inserted table.
ALTER TRIGGER [trigger1] on [dbo].[table]
instead of insert
as
declare #secuencia bigint, #ID_PERSONA VARCHAR;
select #secuencia = SECUENCIA from inserted
select #ID_PERSONA = ID_PERSONA from inserted
if #secuencia is null begin
set inserted.SECUENCIA = NEXT VALUE FOR SEQ_BIOINTEG --(Sequence)
end
i dont know how to edit inserted table.
You do not. That table is read only.
Note how your trigger also says:
instead of insert
There is no way to edit the inserted table.
What you do instead, is setting up an INSERT command for the original table, using the data from the inserted table to filter to the ROWS of inserted - mostly by a join.
Changing inserted makes no sense, logically - because triggers in SQL are one of two things:
INSTEAD OF - then there is no actual insert happening for inserted to start with. Instead of doing the insert, the trigger is called. As such, changing inserted - makes no sense.
AFTER - then the insert already happened (and you UPDATE the rows). As the trigger runs after the update, changing inserting makes no sense.
Note that I say ROWS - your trigger has one very basic error: it assumes inerted contains ONE row. It is a table - it is possible the changes come from an insert statement that inserts multiple rows (which is trivial, i.e. select into, or simply an insert with values for multiple rows). Handle those.
select #ID_PERSONA = ID_PERSONA from inserted
Makes NO sense - inserted is a table, so ID_PERSONA from inserted contains what value, if 2 rows are inserted? You must treat inserted like any other table.
Apart from all the varied issues with your trigger code, as mentioned by others, the easiest way to use a SEQUENCE value in a table is to just put it in a DEFAULT constraint:
ALTER TABLE dbo.[table]
ADD CONSTRAINT DF_table_seq
DEFAULT (NEXT VALUE FOR dbo.SEQ_BIOINTEG)
FOR SECUENCIA;

IF EXIST(To check row exist in table) condition not working in SQL Procedure(AS400)

I have one table and two different SQL procedures(AS400) to Insert/Update records to that same table. Both the SQL procedures having IF EXISTS condition to handle the data.
IF EXIST (SELECT 1 FROM TABLE WHERE FIELD001 = 'test') THEN
Update table....
ELSE
INSERT INTO TABLE VALUES ('test')...
ENDIF;
But still am getting duplicate records in my table with mili seconds difference.
Ex.1st record is --> 2017-07-24-04.21.47.485832
2nd record is --> 2017-07-24-04.21.47.487468
These tables could be Inserted/Updated interactively as well as batch. Anyway How come this is possible for duplicate records..?. Please experts give some possibilities where/when/how duplicate records will be inserted.
And also i don't want to fix this with UNIQUE INDEX, PRIMARY KEY etc...
Sorry I didn't attach any coding with this.
Thanks,
Loganathan.
Adding codes here,,,
The table which I mentioned earlier will insert/update from various ways, but we confirmed these records were inserted interactively from a single session using below single procedure.
Original Records in table.
9243548 CUSTYPE 2017-07-10-16.53.09.825860 2017-07-10-16.53.09.825860
9243548 ROYALTY 2017-07-10-16.53.09.485832 2017-07-10-16.53.09.485832
9243548 ROYALTY 2017-07-10-16.53.09.487468 2017-07-10-16.53.09.487468
Calling program:
if v_res_spec_sts <> '' then
if (v_res_spec_sts <> v_current_res_spec_sts
or v_current_res_spec_sts IS NULL) then
call SPCASPECSV (p_resvnum, c_Royalty, v_res_spec_sts,
p_updateUser, p_updateProgram) ;
end if;
end if;
Procedure:
IF EXISTS (SELECT 1 FROM CASPECLPF WHERE RSRES# = P_RSRES#
AND RSCOND = P_RSCOND) THEN
UPDATE CASPECLPF SET
RSSSTS = COALESCE(P_RSSSTS, RSSSTS)
,RSSLCM = TODAYMONTH
,RSSLCD = TODAYDAY
,RSSLCY = TODAYYEAR
,RSSLCU = COALESCE(P_RSSLCU, RSSLCU)
,RSSLCP = COALESCE(P_RSSLCP, RSSLCP)
WHERE RSRES# = P_RSRES# AND RSCOND = P_RSCOND;
ELSE
INSERT INTO CASPECLPF
(
RSRES#
,RSCOND
,RSSSTS
,RSSLCM
,RSSLCD
,RSSLCY
,RSSLCU
,RSSLCP
)
VALUES
(
COALESCE(P_RSRES#, 0)
,COALESCE(P_RSCOND, ' ')
,COALESCE(P_RSSSTS, ' ')
,TODAYMONTH
,TODAYDAY
,TODAYYEAR
,COALESCE(P_RSSLCU, ' ')
,COALESCE(P_RSSLCP, ' ')
);
END IF;
Make sure they are not in different sessions i.e. inserting in one session and not doing the commit, then second session would obviously not find the record inserted in 1st session.
Also if that is not the case, please provide the code.
Because it's not a duplicate.
If you had a primary or unique key defined, the system would have prevented the second process from writing a record at 2017-07-24-04.21.47.487468.
As it is when the second process checked for a record at 2017-07-24-04.21.47.485500, one didn't exist. But by the time the second process inserted a record the first process had also inserted a record.
Even with a primary key, the existence check and insert are two separate operations. You'd still have to monitor for a duplicate key on the insert and handle appropriately.
The MERGE statement is usually preferred for such "upsert" (UPDATE or INSERT) operations. However, even with a atomic merge, a second process could insert a record between existence check & insert. You have to use a locking level of *RR (repeatable read) which basically locks the entire table to ensure that no process can add a record between the existence check and the insert.
With processes inserting microseconds apart, locking the entire table is going to hurt.
You really need to define a primary key, or at least a unique one.

Change column value after INSERT if the value fits criteria?

I have never really worked with Triggers before in MSSQL but I think it'll be what I need for this task.
The structure of the table is as such:
ID|****|****|****|****|****|****|****|TOUROPERATOR
The Tour Operator Code is the code that tells us what company owned the flight we carried out for them. Two of those codes (there are 24 in total) are outdated. Our users requested that those two be changed but the tour operator code is pulled from a database we don't control. The FlightData table however, we do control. So I was thinking a trigger could change the tour operator code if it was one of the two outdated ones, to the correct ones instead respectively when they were inserted.
So I went into good ol' SQL Management Studio and asked to make a trigger. It gave me some sample code and here is my Pseudo Code below:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER ChangeProvider
ON FlightData
AFTER INSERT
AS
BEGIN
IF(TheInsertedValue == Criteria)
UPDATE FlightData
SET TheInsertedValue = NewValue
ENDIF
END
GO
I am not that good with this type of Database Programming so excuse my mistakes.
How would I go about doing this?
You could add a computed column to your table instead of adding a trigger.
Then the new column could just use a case statement to either show
the original TourOperator column value or the new value you wanted.
You'd add a new column to your table like this
TourOperatorCorrect = CASE WHEN TourOperator = 'Whatever value' THEN 'ChangedValue'
--I just want to use what I have already in the TourOperator column
ELSE TourOperator
END AS VARCHAR(50)
Basics of computed columns are here - https://msdn.microsoft.com/en-ie/library/ms188300.aspx
Your misconception here is that the trigger runs once per inserted value - it is in fact run once per insert statement, so you can and will find more than one row inserted at once.
You'll find that your inserted values are in the pseudo table inserted, which has the same structure as your FlightData table in this case. You write a select statement against that, specifying any criteria you wish.
However, it's not immediately clear what your logic is - does the FlightData table you are updating in your trigger only have one row? Do you update every row in the table with the newest inserted value? It is hard to understand what you are trying to now, and what the purpose of the table and this trigger are - let alone what you would want to do if you inserted more than one row at once.
When inserted table contains mutiple rows,your code will fail,so change code to work with inserted table as whole
UPDATE F
SET f.TheInsertedValue = i.value
from inserted i
join
Flighttable F
on f.matchingcolumn=i.matchingcolumn
and i.somevalue='criteria'

Trigger - After insert and delete example

I have a requirement as a trigger should get fired when any row is inserted or deleted from table FAB which contains num as unique value. and depending upon that num value, another table should be update.
e.g.
FAB table
num code trs
10 A2393 80
20 B3445 780
Reel table
reelnr num use flag
340345 10 500 1
when num 10 from FAB table gets deleted(or any new num gets inserted), the trigger should get fired and should check the reel table which contains that num value and give the reelnr.
How to proceed with this?
you can Use Inserted & Deleted Table in SQL
These two tables are special kind of table that are only available inside the scope of the triggers.
If you tries to use these tables outside the scope of Triggers then you will get Error.
Inserted : These table is use to get track of any new records that are insert in the table.
Suppose there are Six rows are inserted in your table then these table will consist of all the six rows that are inserted.
Deleted : These table is used to track all the Deleted record from your tables.
Last delete rows will be tracked by these table.
For Insert :
CREATE TRIGGER TR_AUDIT_Insert
ON Reel_table
FOR INSERT
AS
BEGIN
INSERT INTO Reel_table (reelnr, num, use, flag)
SELECT
reelnr,
num,
use,
flag
FROM
INSERTED
END
For Delete :
CREATE TRIGGER TR_AUDIT_Delete
ON Product
FOR DELETED
AS
BEGIN
INSERT INTO Reel_table (reelnr, num, use, flag)
SELECT
reelnr,
num,
use,
flag
FROM
DELETED
END
Note :
I don't know from where these three reelnr, use flag values you are getting
So, Please modify this as per your need.
This is the format of the Triggers that normally we use.
You also can do this by using single trigger also
I dont know what is your exact requirement
If you want to achieve by only single Trigger then you can refer this link :
Refer

A thread safe way to check if a row exists before inserting - Is my code correct? [duplicate]

This question already has answers here:
Only inserting a row if it's not already there
(7 answers)
SQL MERGE statement to update data
(6 answers)
Closed 9 years ago.
I have a table "INSERTIF" which looks like this -
id value
S1 s1rocks
S2 s2rocks
S3 s3rocks
Before inserting a row into this table, I wanted to check if the given id exists or not. If it does not exist, then insert. Else, just update the value. I want to do this in a thread safe way. Can you tell me if my code is correct or not ? I tried it and it worked but, I want to be sure that I am not missing anything like performance issues.
EDIT 1- I want to use this code to insert millions of rows, one at a time. Each insert statement is wrapped around the code I have shown.
EDIT 2 - I do not want to use the UPDATE part of my code, only inserting is enough.
I do NOT want to use MERGE because it works with only SQL server 2008 and above
Thanks.
Code -
-- no check insert
INSERT INTO INSERTIF(ID,VALUE)
VALUES('S1', 's1doesNOTrock')
--insert with checking
begin tran /* default read committed isolation level is fine */
if not exists
(select * from INSERTIF with (updlock, rowlock, holdlock)
where ID = 'S1')
BEGIN
INSERT INTO INSERTIF(ID,VALUE)
VALUES('S1', 's1doesNOTrock')
END
else
/* update */
UPDATE INSERTIF
SET VALUE = 's1doesNOTrock'
WHERE ID = 'S1'
commit /* locks are released here */
Code to create table -
CREATE TABLE [dbo].[INSERTIF](
[id] [varchar](50) NULL,
[value] [varchar](50) NULL
)
INSERT [dbo].[INSERTIF] ([id], [value]) VALUES (N'S1', N's1rocks')
INSERT [dbo].[INSERTIF] ([id], [value]) VALUES (N'S2', N's2rocks')
INSERT [dbo].[INSERTIF] ([id], [value]) VALUES (N'S3', N's3rocks')
Your question is about the thread-safety of your code. Succinctly, no — it is not thread-safe. (But see below where isolation is discussed.)
You have a (smallish) window of vulnerability because of the TOCTOU (Time of Check, Time of Use) issue between your 'not exists' SELECT and the corresponding action. Assuming you have a unique (primary) key constraint on the id column, you should use the 'Easier to Ask Forgiveness than Permission' paradigm rather than the 'Look Before You Leap' paradigm (see EAFP vs LBYL).
That means you should determine which of two operation sequences you're going to use:
INSERT, but UPDATE if it fails.
UPDATE, but INSERT if no rows are updated.
Either works. If the work will be mostly insert and occasionally update, then 1 is better than 2; if the work will be mostly update with the occasional insert, then 2 is better than 1. You might even work adaptively; keep a track of what happened in the last N rows (where N might be as few as 5 or as many as 500) and use a heuristic to decide which to try on the new row. There still could be a problem if the INSERT fails (because the row existed) but the UPDATE updates nothing (because someone deleted the row after the insert failed). Similarly, there could still be a problem with UPDATE and INSERT too (no row existed, but one was inserted).
Note that the INSERT option depends wholly on a unique constraint to ensure that duplicate rows are not inserted; the UPDATE option is more reliable.
You also need to consider your isolation level — which might change the original answer. If your isolation is high enough to ensure that after the 'not exists' SELECT is executed, no-one else will be able to insert the row that you determined did not exist, then you may be OK. That gets into some nitty-gritty understanding of your DBMS (and I'm not an SQL Server expert).
You'll need to think about transaction boundaries, too; how big a transaction would be appropriate, especially if the source data has a million entries.
This technique is typically called UPSERT. It can be done in SQL Server using MERGE.
It works like this:
MERGE INTO A_Table
USING
(SELECT 'data_searched' AS Search_Col) AS SRC
-- Search predicates
--
ON A_Table.Data = SRC.Search_Col
WHEN MATCHED THEN
-- Update part of the 'UPSERT'
--
UPDATE SET
Data = 'data_searched_updated'
WHEN NOT MATCHED THEN
-- INSERT part of the 'UPSERT'
--
INSERT (Data)
VALUES (SRC.Search_Col);
Also see http://www.sergeyv.com/blog/archive/2010/09/10/sql-server-upsert-equivalent.aspx
EDIT: I see you're using an older SQL Server. In that case you must use multiple statements.