Resolve concurency during updating table in Sybase - select

I have a procedure in Sybase with the following code.
begin transaction get_virtual_acc
UPDATE store_virtual_acc SET isProc = 1, Uid = #uid, DateReserv = getdate()
from store_virtual_acc (index idx_id) WHERE id = (SELECT min(id) FROM store_virtual_acc (index idx_uid) where Uid = null and isProc = null)
commit transaction get_virtual_acc
The problem is that when the procedure is called multiple users concurently they can receive the same min(id) and update same row in the table with different value #uid. The result is a distortion of the data. It is necessary to achieve a result, that if the line has already selected for update a single user, the other can't select it. Table have lock type datarows.
Tried to use a transaction-level locking as follows
set transaction isolation level 3
before the transaction begin but aplication wich call the procedure get exception
java.sql.SQLException: Your server command (family id # 0, process id # 530) encountered a deadlock situation. Please re-run your command.
I would be grateful for any help.

Try something like this:
begin transaction get_virtual_acc
UPDATE store_virtual_acc SET isProc = 1, Uid = #uid, DateReserv = getdate()
from store_virtual_acc (index idx_id) WHERE id = (SELECT min(id) FROM store_virtual_acc (index idx_uid) holdlock where Uid = null and isProc = null )
commit transaction get_virtual_acc
The keyword is holdlock

Related

Is the cursor variable updated when updating a row?

In the code below (stored procedure body), whether the value of the cursor field is automatically updated after UPDATE or not? If not, is the Close / Open command sufficient again or not?
I didn't find any description that included this, it was just the FOR SELECT cursors in all of them.
DECLARE VARIABLE FCU_VALIDATE TYPE OF COLUMN FCU_CTRL.FCU_VAL_WHEN_IMP;
DECLARE FCU_DOC_MSTR CURSOR FOR
(SELECT * FROM FCU_DOC_MSTR
WHERE FCU_DOC_APN = :APNUMBER
AND FCU_DOC_ID = :DOCID);
BEGIN
OPEN FCU_DOC_MSTR;
FETCH FIRST FROM FCU_DOC_MSTR;
-- CHECK CONTROL FILE SETTINGS
FCU_VALIDATE = COALESCE((SELECT FCU_VAL_WHEN_IMP FROM FCU_CTRL
WHERE FCU_INDEX1 = 1), FALSE);
IF (FCU_VALIDATE = TRUE) THEN
BEGIN
-- IF EXIST INVALID ITEM DETAIL LINE, SET DOCUMENT STATUS TO INVALID
IF ((SELECT COUNT(*) FROM FCU_ITEM_DET
WHERE FCU_ITEM_APN = :FCU_DOC_MSTR.FCU_DOC_APN
AND FCU_ITEM_DOC_ID = :FCU_DOC_MSTR.FCU_DOC_ID
AND FCU_ITEM_STATUS != '0') > 0) THEN
UPDATE FCU_DOC_MSTR
SET FCU_DOC_STATUS = '90'
WHERE CURRENT OF FCU_DOC_MSTR;
END
-- CHECK DOCUMENT STATUS IS IMPORTED AND NO ERROR EXIST SET STATUS TO IMPORTED
IF (FCU_DOC_MSTR.FCU_DOC_STATUS = '99') THEN
UPDATE FCU_DOC_MSTR
SET FCU_DOC_STATUS = '0'
WHERE CURRENT OF FCU_DOC_MSTR;
IF (FCU_VALIDATE = TRUE) THEN
BEGIN
IF (FCU_DOC_MSTR.FCU_DOC_STATUS = '0') THEN
UPDATE FCU_DOC_MSTR
SET FCU_DOC_STATUS = '1'
WHERE CURRENT OF FCU_DOC_MSTR;
-- UPDATE FILE STATUS
IF ((SELECT COUNT(*) FROM FCU_DOC_MSTR
WHERE FCU_DOC_FILE_ID = :FCU_DOC_MSTR.FCU_DOC_FILE_ID
AND FCU_DOC_STATUS != '1') > 0) THEN
UPDATE FCU_FILE_MSTR
SET FCU_FILE_STATUS = '90'
WHERE FCU_FILE_ID = :FCU_DOC_MSTR.FCU_DOC_FILE_ID;
ELSE
UPDATE FCU_FILE_MSTR
SET FCU_FILE_STATUS = '1'
WHERE FCU_FILE_ID = :FCU_DOC_MSTR.FCU_DOC_FILE_ID;
END
CLOSE FCU_DOC_MSTR;
END
If the update is done through the cursor (using UPDATE ... WHERE CURRENT OF _cursor_name_), then the cursor record variable for the current row is also updated.
See this fiddle for a demonstration.
This was not documented in the Firebird 3.0 Release Notes, but it was documented in the doc/sql.extensions/README.cursor_variables.txt included with your Firebird installation. This is also been documented in the Firebird 3.0 Language Reference, under FETCH:
Reading from a cursor variable returns the current field values. This
means that an UPDATE statement (with a WHERE CURRENT OF clause)
will update not only the table, but also the fields in the cursor
variable for subsequent reads. Executing a DELETE statement (with a
WHERE CURRENT OF clause) will set all fields in the cursor variable
to NULL for subsequent reads

Unable to update rows individually

I am trying to update our patient table within our system, but due to a connection we have with the state that sends modifications to that table to an external system I'm unable to do mass updates due to several triggers in our system (Microsoft SQL Server 2008 R2). The main piece of code in the trigger that is preventing
IF (#numrows > 1)
BEGIN
IF ##TRANCOUNT > 0 ROLLBACK TRANSACTION
SELECT #errmsg = OBJECT_NAME(##PROCID) + ' : more than one row is updated in table Patient'
RAISERROR(#errmsg,16,21)
RETURN
END
I cannot simply shut these triggers off where it would break a lot of things, so to do what would be a simple act of
update patient set security_level = '2'
where security_level = '1'
I used the following code which used to work in prior versions
declare #tmp_table table(
PRG int identity(1,1) Primary Key,
patient_id int
)
declare #start_value int = 1,
#finish_value int,
#patient_id int
Insert Into #tmp_table(patient_id ) Select patient_id From patient where security_level = '1'
Select #finish_value = max(PRG) From #tmp_table
While #start_value <= #finish_value
Begin
--now get a key for patient and store in variables
Select #patient_id = patient_id
From #tmp_table
Where PRG = #start_value
--.. and now update by key
Update patient
set security_level = '2'
Where patient_id = #patient_id
Set #start_value = #start_value + 1
End
I get the following error upon running that code
Msg 50000, Level 16, State 21, Procedure tU_Patient_HL7, Line 64
tU_Patient_HL7 : more than one row is updated in table Patient
Msg 3609, Level 16, State 1, Line 22
The transaction ended in the trigger. The batch has been aborted.
Any idea how I could tweak this or recode this to update the security level of all patients who have a security level set at 1 and switch it to 2?
Update
Would there be any way I could loop
Update top (1) patient
set security_level = '2'
where security_level = '1'
Until all rows are affected? That would work as well.
With out full code ,it is hard .I am guessing your update statement is conflicting with below peice of code..
IF (#numrows > 1)
even though you use
Update patient
set security_level = '2'
Where patient_id = #patient_id
Your update query may affect more than one row.So my best bet would be to tweak your update query to below or change trigger if you can which is desirable
Update top (1) patient
set security_level = '2'
Where patient_id = #patient_id
If you add to your update code a "GO 100", that should do the trick. You may need to put a delay in there as well if it updates too fast for the trigger.
Update top (1) patient
set security_level = '2'
where security_level = '1'
GO 100
The number of executions (i.e. 100 in my example) is up to you.

DB2 Query : insert data in history table if not exists already

I have History table and transaction table.....and reference table...
If status in reference table is CLOSE then take those record verify in History table if not there insert from transaction table..... wiring query like this .... checking better one... please advice.. this query can be used for huge data ?
INSERT INTO LIB1.HIST_TBL
( SELECT R.ACCT, R.STATUS, R.DATE FROM
LIB2.HIST_TBL R JOIN LIB1.REF_TBL C
ON R.ACCT = C.ACCT WHERE C.STATUS = '5'
AND R.ACCT NOT IN
(SELECT ACTNO FROM LIB1.HIST_TBL)) ;
If you're on a current release of DB2 for i, take a look at the MERGE statement
MERGE INTO hist_tbl H
USING (SELECT * FROM ref_tbl R
WHERE r.status = 'S')
ON h.actno = r.actno
WHEN NOT MATCHED THEN
INSERT (actno,histcol2, histcol3) VALUES (r.actno,r.refcol2,r.refcol3)
--if needed
WHEN MATCHED
UPDATE SET (actno,histcol2, histcol3) = (r.actno,r.refcol2,r.refcol3)

update data using loop in sql syntax

I work with postgreSQL
I want to update email of all my users using sql
I have a table named user that contains 500 users,
so I think that I should use a loop in my sql syntax
For example when the table contains 4 users, I want the email for these users to become :
user1#hotmail.fr
user2#hotmail.fr
user3#hotmail.fr
user4#hotmail.fr
in java it should be like this
String newValue=null;
for(int i=0;i<list.size();i++)
{
newValue="user"+i+"#hotmail.fr";
// make update
}
I think that I should use plsql syntax
updated :
I try without success with this code :
BEGIN
FOR r IN SELECT * from user_
LOOP
NEXT r;
UPDATE user_ SET emailaddress = CONCAT('user',r,'#hotmail.fr')
END LOOP;
END
I solved the problem using this query :
UPDATE user_ SET emailaddress='user' || col_serial || '#hotmail.fr' FROM
(SELECT emailaddress, row_number() OVER ( ORDER BY createdate) AS col_serial FROM user_ ORDER BY createdate) AS t1
WHERE user_.emailaddress=t1.emailaddress

Cannot insert NULL value into column error

I have a issue where I want to update a column in a table and with a trigger to update same column but in another table. It says I cannot insert NULL but I can't seem to understand from where it gets that NULL value. This is the trigger:
CREATE TRIGGER Custom_WF_Update_WF_DefinitionSteps_DefinitionId ON WF.Definition
AFTER UPDATE AS BEGIN
IF UPDATE(DefinitionId)
IF TRIGGER_NESTLEVEL() < 2
BEGIN
ALTER TABLE WF.DefinitionSteps NOCHECK CONSTRAINT ALL
UPDATE WF.DefinitionSteps
SET DefinitionId =
(SELECT i.DefinitionId
FROM inserted i,
deleted d
WHERE WF.DefinitionSteps.DefinitionId = d.DefinitionId
AND i.oldPkCol = d.DefinitionId)
WHERE WF.DefinitionSteps.DefinitionId IN
(SELECT DefinitionId FROM deleted)
ALTER TABLE WF.DefinitionSteps CHECK CONSTRAINT ALL
END
END
This update statement works just fine:
UPDATE [CCHMergeIntermediate].[WF].[Definition]
SET DefinitionId = source.DefinitionId + 445
FROM [CCHMergeIntermediate].[WF].[Definition] source
But this one fails:
UPDATE [CCHMergeIntermediate].[WF].[Definition]
SET DefinitionId = target.DefinitionId
FROM [CCHMergeIntermediate].[WF].[Definition] source
INNER JOIN [centralq3].[WF].[Definition] target
ON (((source.Name = target.Name) OR (source.Name IS NULL AND target.Name IS NULL)))
I get the following error:
Msg 515, Level 16, State 2, Procedure Custom_WF_Update_WF_DefinitionSteps_DefinitionId, Line 7
Cannot insert the value NULL into column 'DefinitionId', table 'CCHMergeIntermediate.WF.DefinitionSteps'; column does not allow nulls. UPDATE fails.
If I do a select instead of the update statement, like this:
SELECT source.DefinitionId, target.DefinitionId
FROM [CCHMergeIntermediate].[WF].[Definition] source
INNER JOIN [centralq3].[WF].[Definition] target
ON (((source.Name = target.Name) OR (source.Name IS NULL AND target.Name IS NULL)))
I get this result:
http://i.stack.imgur.com/3cZsM.png (sorry for external link, I don't have enaugh reputation to post image here )
What am I doing wrong? What I don't see? What am I missing..?
The problem was in the trigger at the condition. I modified the second where from i.oldPkCol = d.DefinitionId to i.oldPkCol = **d.oldPkCol** and it worked.
UPDATE WF.DefinitionSteps
SET DefinitionId =
(SELECT i.DefinitionId
FROM inserted i,
deleted d
WHERE WF.DefinitionSteps.DefinitionId = d.DefinitionId
AND i.oldPkCol = **d.oldPkCol**)
WHERE WF.DefinitionSteps.DefinitionId IN
(SELECT DefinitionId FROM deleted)