sql server UPDATE TRIGGER doesn't fire - sql-server-2008

i have a trigger like below, the logic is to change FID status after fidRule status changed.
in my app, i update 1 row in each statement,
but i found sometimes(very rare) the trigger not firing.
ALTER TRIGGER [dbo].[triggerSetFIDStatus]
ON [dbo].[FIDRules]
AFTER UPDATE
AS
BEGIN
set nocount on
DECLARE #ruleStatus INT
DECLARE #newRuleStatus INT
DECLARE #FIDAlertStatus INT
DECLARE #FIDId INT
DECLARE #isFIDEnabled int
DECLARE #ruleId INT
SELECT #ruleStatus = deleted.alertStatus,
#FIDId = deleted.FIDID,
#ruleId = deleted.id
from
deleted
SELECT #newRuleStatus = inserted.alertStatus
from
inserted
SELECT #FIDAlertStatus = alertStatus,
#isFIDEnabled= isEnabled
FROM FID
WHERE id = #FIDId
IF #FIDAlertStatus <> #newRuleStatus
BEGIN
-- change FID-status by FIDRule-status
UPDATE [dbo].[FID] SET alertStatus=#newRuleStatus WHERE id=#FIDId
END
IF #newRuleStatus >= 0 AND #newRuleStatus <> #ruleStatus
UPDATE [dbo].[FIDRules] SET isAlertStatChanged=1, AlertStatChangeTime = SYSUTCDATETIME() WHERE id=#ruleId
END

The trigger will not be fired if the UPDATE statement fails or another triggers fails to execute before this trigger is fired.
One comment about your trigger itself:
You are expecting one records from DELETED which is not always correct.
Please make your trigger robust enough in case DELETED contains multiple records
-- What if deleted contains multiple records?
SELECT #ruleStatus = deleted.alertStatus,
#FIDId = deleted.FIDID,
#ruleId = deleted.id
FROM
deleted
You can either use SELECT TOP(1) or make sure your trigger is able to handle multiple records from the DELETED list.

Related

MySql trigger not works

I have 3 tables
tbl_payments(pay_id,date,amount,description,-------)
tbl_pay_trans(pay_id,trans_id)
tbl_transactions(trans_id,trans_date,trans_amount,trans_description,-----)
'tbl_transaction' has the same data from the 'tbl_payments' along with some other values. To maintain the relationship between the two tables I use 'tbl_pay_trans'. What I want to do is, when an update done on tbl_payments(amount,description) the same changes need to do in tbl_transactions(trans_amount,trans_description). I wrote a trigger to do that, but it dose not update the tbl_transaction table values as it supposed to.
My trigger is
DELIMITER $$
CREATE TRIGGER update_trans
AFTER UPDATE on tbl_payments
FOR EACH ROW
BEGIN
DECLARE new_amount VARCHAR(50);
DECLARE new_description TEXT;
DECLARE new_pay_id,new_trans_id INT;
SET new_pay_id = OLD.pay_id;
SET new_amount = OLD.amount;
SET new_description = OLD.description;
SELECT trans_id INTO new_trans_id FROM tbl_pay_trans WHERE pay_id = new_pay_id;
UPDATE tbl_transactions SET
trans_amount = new_amount,
trans_description = new_description
WHERE trans_id = new_trans_id;
END$$
DELIMITER ;
Please someone help me to figure out what I did wrong.
It's not updating because you are using OLD on the amount and description columns where you need to use NEW i.e.
SET new_amount = NEW.amount;
SET new_description = NEW.description;
OLD refers to the column value before the update occurred in tbl_payments. See the manual.

MySQL Trigger updates all rows even if a distinct where clause is given

Refer to the following trigger,
create trigger trigger_update_rows after insert on transaction for each row
DECLARE tr_type VARCHAR(15);
DECLARE tr_op VARCHAR(10);
DECLARE tr_amt FLOAT(8,2);
DECLARE tr_qnt INTEGER;
DECLARE item_id INTEGER;
SET tr_type = NEW.TRANSACTION_TYPE;
SET tr_op = (SELECT TRANSACTION_TYPE_OPERATION FROM transaction_type WHERE
TRANSACTION_TYPE_NAME=tr_type limit 1);
SET tr_amt = NEW.TRANSACTION_AMOUNT;
SET tr_qnt = NEW.QUANTITY;
SET item_id = NEW.ITEM_ID;
IF tr_op = 'ADD' THEN
update item set QUANTITY_AVAILABLE=QUANTITY_AVAILABLE-
tr_qnt,QUANTITY_SOLD=QUANTITY_SOLD+tr_qnt,AVAILABLE_GOODS_VALUE =
AVAILABLE_GOODS_VALUE - tr_amt,SOLD_GOODS_VALUE=SOLD_GOODS_VALUE+tr_amt
where ITEM_ID=item_id;
ELSEIF tr_op = 'SUBTRACT' THEN
update item set QUANTITY_AVAILABLE=QUANTITY_AVAILABLE+tr_qnt,QUANTITY_BOUGHT=QUANTITY_BOUGHT+tr_qnt,AVAILABLE_GOODS_VALUE=AVAILABLE_GOODS_VALUE+tr_amt,BOUGHT_GOODS_VALUE=BOUGHT_GOODS_VALUE+tr_amt where ITEM_ID=item_id;
END IF;
END
ITEM_ID is a primary key in the table item and the following is the transaction row inserted
insert into transaction(TRANSACTION_DATE,TRANSACTION_TYPE,ITEM_ID,QUANTITY,TRANSACTION_AMOUNT,ACCOUNT_ID,BUYER,SELLER) values ('2017-08-12','BUY',2,5,500.00,3,1,2);
What is making the above trigger update all rows in item instead following the where clause
You problem is:
where ITEM_ID = item_id;
You may think that one of the item_ids is somehow connected to the variable. It is not.
Rename the variable to something like v_item_id and then use:
where item_id = v_item_id

how to optimise MySql function to work for concurrent users

I am new to MySQL. Please can you advice on how can i modify below function to ensure it does not throw locking errors when called by multiple users at the same time.
CREATE FUNCTION `get_val`(`P_TABLE` VARCHAR(50)) RETURNS int(11)
DETERMINISTIC
BEGIN
DECLARE pk_value INT DEFAULT 0;
DECLARE pk_found INT DEFAULT 0;
SELECT 1 INTO pk_found FROM pk_keys WHERE TABLE_NAME = P_TABLE;
IF pk_found = 1
THEN
UPDATE pk_keys SET TABLE_VALUE = (TABLE_VALUE + 1 ) WHERE TABLE_NAME = P_TABLE;
ELSE
INSERT INTO pk_keys VALUES ( P_TABLE, 1 );
END IF;
SELECT TABLE_VALUE INTO pk_value FROM pk_keys WHERE TABLE_NAME = P_TABLE;
RETURN pk_value;
END
thanks
CREATE FUNCTION `get_val`(`P_TABLE` VARCHAR(50)) RETURNS int(11)
DETERMINISTIC
MODIFIES SQL DATA
BEGIN
DECLARE pk_value INT DEFAULT 0;
IF EXISTS (SELECT 1 FROM pk_keys WHERE TABLE_NAME = P_TABLE)
THEN
SELECT TABLE_VALUE + 1 INTO pk_value FROM pk_keys WHERE TABLE_NAME = P_TABLE FOR UPDATE;
UPDATE pk_keys SET TABLE_VALUE = pk_value WHERE TABLE_NAME = P_TABLE;
ELSE
SET pk_value = 1;
INSERT INTO pk_keys VALUES ( P_TABLE, pk_value );
END IF;
RETURN pk_value;
END
Have a look at SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE Locking Reads
Let us look at another example: We have an integer counter field in a
table child_codes that we use to assign a unique identifier to each
child added to table child. It is not a good idea to use either
consistent read or a shared mode read to read the present value of the
counter because two users of the database may then see the same value
for the counter, and a duplicate-key error occurs if two users attempt
to add children with the same identifier to the table.
Here, LOCK IN SHARE MODE is not a good solution because if two users
read the counter at the same time, at least one of them ends up in
deadlock when it attempts to update the counter.
To implement reading and incrementing the counter, first perform a
locking read of the counter using FOR UPDATE, and then increment the
counter. For example:
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
A SELECT ... FOR UPDATE reads the latest available data, setting
exclusive locks on each row it reads. Thus, it sets the same locks a
searched SQL UPDATE would set on the rows.
Also I replaced your if condition. EXISTS stops as soon as a row is found.

datas are appending everytime on running stored procedure

Am new to Stored procedures.I wrote the stored procedure to copy table from one dtabase to another database.On executing my stored procedures everytime My datas are added in the destination table .My row counts was increasing on every execution.
Please help to resolve the issue.Hope the problem In the loops.
My SP is:
--exec mall
alter procedure mall
as
begin
declare #mallid int
declare #mallname nvarchar(40)
declare #mallstatus nvarchar(40)
declare #malludsuomid nchar(2)
declare #malludsassetcode nvarchar(6)
declare #malludsassettype nvarchar(15)
declare #malludsremarks nvarchar(max)
declare #malludsdwdb int
declare #mallsecterr int
declare #mallassetid int
declare #secterr int
declare #Maxmallid int
declare #mallentityid int
Select #mallentityid = customtable.Bord_TableId From CRM.dbo.Custom_Tables as customtable With (NoLock) Where Upper(Bord_Caption) = Upper('Mall') And Bord_Deleted Is Null
DECLARE cur_address CURSOR FOR
SELECT
udsasset.Asset_ID,udsasset.Asset_Name,udsasset.Asset_Status,udsasset.UOM_ID, udsasset.Asset_Code,udsasset.Asset_Type,udsasset.Remarks,udsasset.DW_Key_Source_DB --,crmterr.TPro_SecTerr
from
CMA_UDS.dbo.Dim_Asset as udsasset
OPEN cur_address
FETCH NEXT FROM cur_address INTO #mallid,#mallname,#mallstatus,#malludsuomid,#malludsassetcode,#malludsassettype,#malludsremarks,#malludsdwdb --,#mallsecterr
WHILE ##FETCH_STATUS = 0
BEGIN
if not exists (select crmmall.mall_MallID from CRM.dbo.Mall as crmmall where crmmall.mall_MallID = #mallid)
begin
exec #Maxmallid = CRM.dbo.crm_next_id #Table_Id=#mallentityid
insert into
CRM.dbo.Mall
(mall_MallID,mall_Name,mall_Status,mall_uds_UOMID,mall_uds_asset_code,mall_uds_asset_type,
mall_uds_remarks,mall_uds_dw_db,mall_CreatedBy,mall_CreatedDate,mall_Secterr,mall_AMOSUploaded,mall_asset_id)
values(#Maxmallid,#mallname,#mallstatus,#malludsuomid,#malludsassetcode,#malludsassettype,#malludsremarks,#malludsdwdb,1,GETDATE(),
#mallsecterr,GETDATE(),#mallid)
end
else
begin
update
CRM.dbo.Mall
set
mall_asset_id=#mallid,mall_Name = #mallname,mall_Status=#mallstatus,mall_uds_UOMID =#malludsuomid,mall_uds_asset_code=#malludsassetcode,
mall_uds_asset_type=#malludsassettype,mall_uds_remarks=#malludsremarks,mall_uds_dw_db=#malludsdwdb,mall_UpdatedBy=1,
mall_UpdatedDate=GETDATE(),mall_Secterr=#mallsecterr,mall_AMOSUploaded=GETDATE()
where
mall_MallID=#mallid
end
FETCH NEXT FROM cur_address INTO #mallid,#mallname,#mallstatus,#malludsuomid,#malludsassetcode,#malludsassettype,#malludsremarks,#malludsdwdb--,#mallsecterr
end
CLOSE cur_address
DEALLOCATE cur_address
End
Why are you inserting crm_next_id as the value in mall_MallID, but using that same id to compare with #mallid to see if the record is already inserted? For example, if you have id 5, and you insert a new record with id 150, it's not going to see that the record is already inserted when you run the SP again. Next run, it will add record with id 151, then 152, and so forth forever. You shouldn't use the same field as both an auto-increment identity and a foreign key reference at the same time...
You either need to use the same #mallid when you insert the new records so they match, or after you generate a new id and insert into the table, update the original record CMA_UDS.dbo.Dim_Asset to have Asset_ID = #mallid so they are linked up properly. Which method you use depends on the meanings of those id's and what constraints you have in your particular application.

sql server trigger for custom PK

I want to generate PK through trigger as it is custom PK.
It is like depending on the member type field, I want to generate member id which is PK.
e.g. if new record's member type is DGIA, then member id will be DGIA1, DGIA2, DGIA3 ...and so on... if member type is DGIL, then member id will be DGIL1, DGIL2, DGIL3 ...and so on...
So, how to write trigger for the same... I have tried as following but it is working for 1st record only.
ALTER TRIGGER [dbo].[next_member_id] ON [dbo].[DAD_MEMBERSHIP] AFTER INSERT
AS
BEGIN
DECLARE #COUNT INT
SET #COUNT=0;
SELECT #COUNT=ISNULL(MAX(CAST(SUBSTRING(DAD_MEMBERSHIP.MEMBER_ID,5,15) AS INT)),0)+1 FROM DAD_MEMBERSHIP where DAD_MEMBERSHIP.MEMBER_TYPE = DAD_MEMBERSHIP.MEMBER_TYPE
update DAD_MEMBERSHIP set DAD_MEMBERSHIP.MEMBER_ID = DAD_MEMBERSHIP.MEMBER_TYPE + CONVERT(varchar,#COUNT)
from DAD_MEMBERSHIP inner join inserted on DAD_MEMBERSHIP.MEMBER_TYPE = inserted.MEMBER_TYPE
END
Triggers operate by batch of records, you cannot assign to a scalar variable and expect it to work for more than one record. You need to rethink your whole process into a set-based process.
I solved the problem using following trigger
ALTER TRIGGER [dbo].[next_member_id]
ON [dbo].[DAD_MEMBERSHIP]
AFTER INSERT
AS
BEGIN
DECLARE #COUNT INT
SET #COUNT=0;
DECLARE #STR VARCHAR(5)
SET #STR=''
select #STR=i.MEMBER_TYPE from inserted i;
SELECT #COUNT=ISNULL(MAX(CAST(SUBSTRING(DAD_MEMBERSHIP.MEMBER_ID,5,15) AS INT)),0)+1
from DAD_MEMBERSHIP where MEMBER_TYPE=#STR
update DAD_MEMBERSHIP set DAD_MEMBERSHIP.MEMBER_ID = #STR + CONVERT(varchar,#COUNT)
from DAD_MEMBERSHIP inner join inserted i on i.MEMBER_TYPE=DAD_MEMBERSHIP.MEMBER_TYPE where DAD_MEMBERSHIP.MEMBER_ID is null
END