Need to wait on specific column state change in SQL - sql

I need to check for the status change of a certain column in the table
I can do it using while loop, where i can get the column value and check the value and break from the loop if value is changed.
i am using SQL server 2008.
is there a better way?
Here is the sample sql query
declare #status int = 1
select #status = status from MyTable with (nolock) where Id = 100034
while #status <> 3
begin
WAITFOR DELAY '00:01'
select #status = status from MyTable with (nolock) where Id = 100034
end

Have you considered to use a trigger instead of an stored procedure? This is exactly, what are triggers for.
CREATE TRIGGER reactOnStatus3
ON MyTable
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
IF Status = 3
EXEC DoTheMagicStoredProcedure;
END;

Related

How to Update a column Before Select?

I am setting a stored procedure for select and I want to update the value of one column in the database Before doing the Select.
This is what I tried but it's not working.
#roleID int and #query varchar(240)
SELECT
EP.Equipe_Projet_Id AS PROJET_ID,
U.USR_ID,
CleRepartition = CASE
WHEN #RoleID = 1 AND #query IS NOT NULL
THEN 100
AND (UPDATE EQUIPE_PROJET SET CleRepartition = 100
WHERE EP.Equipe_Projet_Id = #PROJET_ID AND EP.Role_Id = 3)
ELSE NULL
END
FROM
[EQUIPE_PROJET] EP
Expecting update of column on database and having it's value
i want to update the value of Column CleRepartition in the database while selecting.
This is not possible in a SELECT query. A SELECT retrieves data from the database. An UPDATE modifies data. These are two separate statements and cannot be combined.
You are doing this work in a stored procedure. Within a stored procedure, you can run an UPDATE and SELECT in any order, so you can accomplish both tasks. If you are concerned about data changing in the database between the two statements, you can wrap them in a transaction.
Stored procedure can do update then select after.
So I added the query of update in the beginning, then I do the select.
Like this:
UPDATE EP
SET CleRepartition = CASE
WHEN #RoleID = 1 AND #query IS NOT NULL
THEN 100
AND (UPDATE EQUIPE_PROJET
SET CleRepartition = 100
WHERE EP.Equipe_Projet_Id = #PROJET_ID
AND EP.Role_Id = 3)
ELSE NULL
END
FROM [EQUIPE_PROJET] EP
SELECT
EP.Equipe_Projet_Id AS PROJET_ID,
U.USR_ID,
CleRepartition
FROM
[EQUIPE_PROJET] EP
I hope that this will help someone.

SQL stored procedure waiting and executing sequentially

I have a stored procedure that reads the ID of a row with status x, then immediately sets that rows id to status y.
Since this stored procedure is being called by multiple client apps, somehow the same values are being returned whereas really it 2 executions should not find any in status x.
I'm not using anything other than wrapping the actions in a begin transaction / commit.
Rough example:
Begin Transaction
IF (#Param = '2') -- all
BEGIN
#resultID = (SELECT ... WHERE STATUS_ID = X
END
ELSE
BEGIN
#resultID = (SELECT ... WHERE STATUS_ID = X
END
IF (#ResultID > 0)
BEGIN
UPDATE JOB_QUEUE SET STATUS_ID = Y WHERE ID = #ResultID
END
COMMIT
SELECT * from JOB_QUEUE WHERE ID = #ResultID
Somehow the query has returned the same #resultID from the table .. so I would presume I need some locking or something to prevent this.
Is there a method to ensure that executions of the stored procedure at the same time result in one executing and then the other (sequentially)?
Thanks.
The simple answer is to speed up the whole process - if its a slow running query, then the select can run before the update is finished.
If you need to select the values for some other report, you could effectively run the update as the first statement, and use the OUTPUT keyword to return the ID's of the updated records eg:
UPDATE JOB_QUEUE
SET STATUS_ID = Y WHERE STATUS_ID = X
OUTPUT inserted.ID

Sometimes SQL Server trigger is not firing

I created a trigger on my recharge table. It updates the balance of onaccountregistry table.
But sometimes when inserting rows into my recharge table it is not firing the trigger. Then values are mismatch. This recharge table insert rows every time.
I created the trigger as follows. This is not a replicated table. I'm using SQL Server 2008 Enterprise edition.
Please help me solve this matter
CREATE TRIGGER [dbo].[RechargeRefund]
ON [dbo].[ISRecharge]
FOR INSERT
AS
declare #tin char(9)
declare #depocd char(1)
declare #oldvalue money
declare #newvalue money
begin
select #tin = inserted.tin_subtin from inserted
select #depocd = inserted.updatetype from inserted
select #newvalue = inserted.DepositAmt from inserted
select #oldvalue = Totdeposit from ISOnAcctRegistry where tin_subtin = #tin
end
if #depocd ='1'
begin
update ISOnAcctRegistry
set Totdeposit = #oldvalue + #newvalue
where tin_subtin = #tin
end
if #depocd ='2'
begin
update ISOnAcctRegistry
set Totdeposit = #oldvalue - #newvalue
where tin_subtin = #tin
end
GO
As #marc points out, writing assuming a single row in inserted is bad - it can even be possible for your 3 selects from inserted to assign values to your 3 variables from 3 different (arbitrary) rows from inserted.
What you probably want is:
update i1
set Totdeposit = Totdesposit + t2.Total
from ISOnAcctRegistry i1
inner join
(select
tin_subtin,
SUM(CASE updatetype
WHEN 1 THEN DepositAmt
WHEN 2 THEN -DepositAmt
ELSE 0 END) as Total
from inserted
group by tin_subtin) t2
on
i1.tin_subtin = t2.tin_subtin
But you might be able to replace this work (and this column in ISOnAcctRegistry) with an indexed view built on ISRecharge - with some limitations, you can build a view that automatically performs a SUM across the rows in ISRecharge, and SQL Server would take responsibility for maintaining the value in the background for you.
Obviously, at present, your trigger doesn't account for any UPDATE or DELETE activity on ISRecharge. An indexed view would.
Well, of course it won't work - you're assuming that the trigger fires once per row inserted.
But that's NOT the case.
The trigger fires once per INSERT batch, and the pseudo-table Inserted might contain multiple rows!
If you did get an INSERT with more than one row - which row did your statements here select ?
select #tin = inserted.tin_subtin from inserted
select #depocd = inserted.updatetype from inserted
select #newvalue = inserted.DepositAmt from inserted
select #oldvalue = Totdeposit from ISOnAcctRegistry where tin_subtin = #tin
You need to rewrite your trigger so that it will handle multiple rows in Inserted - then it'll work every time.

SQL trigger to prevent bit column from being updated from 1 to 0?

Given a column with bit type in SQL Server 2008, how can I write a trigger to allow updates from 0 to 1, but disallow updating from 1 to 0?
In other words, once the bit is set to 1, it should always be 1.
The trigger must work for multiple updates, e.g. :
UPDATE Table SET BitField = 0
Should fail for any row where BitField = 1.
EDIT: To give some background, the bit/flag in question marks whether or not a monetary transaction needs to be processed. If the bit =1, the transaction has already been processed. If the bit is reset to 0, the transaction may be duplicated, so I need to enforce at the database level that the bit can not be reset to 0.
I need to protect against direct queries run against the database as well as application level bugs. I can't be sure that a stored procedure will always be used to update the table, so I believe a trigger is the only way to enforce this logic.
Looks like you are in need of a simple after trigger
CREATE TABLE YourTable(
PK int Primary key,
bitCol bit
)
CREATE TRIGGER YourTableTrigger
ON YourTable
AFTER UPDATE
AS
DECLARE #nrOfViolations int
select #nrOfViolations = count(*) from deleted d
join YourTable t on d.PK = t.PK
where d.bitCol = 1 and t.bitCol = 0
if #nrOfViolations > 0
BEGIN
RAISERROR('Failed', 16, 1);
ROLLBACK TRANSACTION
END
I wouldn't bury it in a Trigger. I'd have your stored procedure (SP) that updates the table do a check on the value. For example:
CREATE PROCEDURE dbo.proc_update_my_table
#id AS INT,
-- Whatever other params you need
#the_bit_field AS BIT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #existing_value AS BIT
SELECT #existing_value = the_bit_field FROM dbo.Table1 t WHERE t.id = #id
IF #existing_value = 1 AND #the_bit_field = 0
BEGIN
RAISERROR('Fail.', 10, 1)
RETURN -1
END
-- Update the table as normal.
END
GO
Using a Trigger is kind of like trying to get the thief (the error) out of the house after he got in through the open front door (the SP's query). Lock the front door instead ;)
One way would be an instead of trigger that lets all the updates through except anything that changes the bitfield once it's equal to 1. In that case it lets all the updates through except the bitfield change.
CREATE TRIGGER OneWayBitChange
ON YourTable
INSTEAD OF UPDATE
AS
BEGIN
UPDATE YourTable SET /* update all fields from original update except bitfield */
Field1 = i.Field1,
Field2 = i.Field2,
Field3 = i.Field3
FROM YourTable
INNER JOIN Inserted i ON i.PrimaryKey = YourTable.PrimaryKey
UPDATE YourTable SET /* update bitfield only if it's not already a 1 */
BitField = i.BitField
FROM YourTable
INNER JOIN Inserted i ON i.PrimaryKey = YourTable.PrimaryKey
WHERE IsNull(YourTable.BitField,0) < 1
END
GO
The above will allow all updates accept the one field when going from 1 to anything else (0, or null).
If you want to cancel any update on that row when an attempt is made on the bit field you can modify the body like this:
UPDATE YourTable SET /* update all except bitfield changes from 1 to 0 */
Field1 = i.Field1,
Field2 = i.Field2,
Field3 = i.Field3,
BitField = i.BitField
FROM YourTable
INNER JOIN Inserted i ON i.PrimaryKey = YourTable.PrimaryKey
WHERE IsNull(BitField,0) = 0 OR IsNull(i.BitField,0) = 1

How to use trigger for update in SQL Server 2005

I have a table called tbl_gallery which has a column of datatype bit called isActive.
When the user updates the IsActive value, other rows with IsActive = true will be automatically turned to false.
How can do it with updated trigger?
Please help
I think you want something like:
CREATE TRIGGER trgGalleryActive
ON dbo.tbl_gallery
FOR UPDATE
AS
BEGIN
UPDATE g
-- Update all other gallery rows for this same user to false
SET g.IsActive = 0
FROM tbl_gallery g
INNER JOIN inserted i
on g.UserPK = i.UserPK
WHERE
-- However, we don't want current inserted records to be updated
g.TablePK <> i.TablePK
-- As per Marc's comment - don't update existing inactive rows unnecessarily
AND g.IsActive = 1
-- Only if this record is active should any of this happen
AND i.IsActive = 1
END
Trigger for update second table after updated first table :
CREATE TRIGGER update_table_cityUpdated_afterTable_cityUpdate
ON Table_city
AFTER UPDATE AS
BEGIN
DECLARE #cityId AS BIGINT
DECLARE #stateId AS BIGINT
DECLARE #CityName AS NVARCHAR(200)
SELECT #cityId=cityId FROM INSERTED
SELECT #stateId= stateId FROM INSERTED
SELECT #CityName= CityName FROM INSERTED
UPDATE table_cityUpdated
SET
[dbo].[table_cityUpdated].stateId=#stateId,
[dbo].[table_cityUpdated].CityName=#CityName
WHERE [dbo].[table_cityUpdated].cityId=#cityId
END
;