I'm new to SQL Server, and I'm trying to build a simple update trigger that writes a row to a staging table whenever the column ceu_amount is updated from zero to any number greater than zero.
From using PRINT statements, I know that the variables are containing the correct values to execute the INSERT statement, but no rows are being inserted.
Can you help?
CREATE TRIGGER [dbo].[TRG_Product_Function_Modified] ON [dbo].[Product_Function]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
--
-- Variable definitions
--
DECLARE #product_code_new as varchar(31)
DECLARE #product_code_old as varchar(31)
--
-- Check if the staging table needs to be updated.
--
SELECT #product_code_new = product_code FROM Inserted where ISNULL(ceu_amount,0) > 0;
SELECT #product_code_old = product_code FROM Deleted where ISNULL(ceu_amount,0) = 0;
IF #product_code_new IS NOT NULL
AND #product_code_old IS NOT NULL
INSERT INTO Product_Function_Staging VALUES (#product_code_new,CURRENT_TIMESTAMP);
END;
This part of code looks suspicious to me..
SELECT #product_code_new = product_code FROM Inserted where ISNULL(ceu_amount,0) > 0;
SELECT #product_code_old = product_code FROM Deleted where ISNULL(ceu_amount,0) = 0;
IF #product_code_new IS NOT NULL
AND #product_code_old IS NOT NULL
INSERT INTO Product_Function_Staging VALUES (#product_code_new,CURRENT_TIMESTAMP);
The above will work fine ,if there is only one row updated,what if there is more than one value..the product_code will default to last value
You can change the above part of code to below
Insert into Product_Function_Staging
select product_code ,CURRENT_TIMESTAMP from inserted where product_code is not null
You will get undetermined values for #product_code_new if there are more than one rows updated with ceu_amount>0; Similar for #product_code_old if more than one rows updated with ceu_amount NULL or equal 0.
Can you post some sample data?
I would not use variables like that in a trigger, since what causes the trigger could be an update to more than one row, at which point you would have multiple rows in your updated and deleted tables.
I think we can more safely and efficiently make this insert with one simple query, though I'm assuming you have a unique key to use:
CREATE TRIGGER [dbo].[TRG_Product_Function_Modified] ON [dbo].[Product_Function]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO Product_Function_Staging
SELECT i.product_code, CURRENT_TIMESTAMP
FROM inserted i
JOIN deleted d ON i.product_code = d.product_code -- assuming product_code is unique
WHERE i.ceu_amount > 0 -- new value > 0
AND ISNULL(d.ceu_amount, 0) = 0; -- old value null or 0
END;
I'm not sure where you need to check for nulls in your data, so I've made a best guess in the where clause.
Try using this
CREATE TRIGGER [dbo].[Customer_UPDATE]
ON [dbo].[Customers]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CustomerId INT
DECLARE #Action VARCHAR(50)
SELECT #CustomerId = INSERTED.CustomerId
FROM INSERTED
IF UPDATE(Name)
BEGIN
SET #Action = 'Updated Name'
END
IF UPDATE(Country)
BEGIN
SET #Action = 'Updated Country'
END
INSERT INTO CustomerLogs
VALUES(#CustomerId, #Action)
END
Related
I'm reaching out for some help on this trigger I'm trying to get working.
Basically this is what I'm trying to do.
We have DMS software that writes to a Database and on a particular INSERT value I want the trigger to fire.
This is an example of an INSERT statement that will get processed.
INSERT INTO DOCSADM.ACTIVITYLOG (CR_IN_USE,ACTIVITY_DESC,BILLED_ON,BILLABLE,PAGES,KEYSTROKES,
TYPE_TIME,ELAPSED_TIME,TYPIST,AUTHOR,START_DATE,ACTIVITY_TYPE,REF_DOCUMENT,REF_LIBRARY,APPLICATION,VERSION_LABEL,DOCNUMBER,SYSTEM_ID)
VALUES ('','DOCSFusion','1753-01-01','',0,0,0,0,1920,1920,'2020-08-26T10:17:56',**115**,0,-1,1173,'',75,3252)
but I only want the trigger to fire when we see a value of 115 for the bold section in the INSERT statement (the Activity_type value).
For all other values that re not 115 I don't want to do anything.
This is what I have so far:
CREATE TRIGGER BW_TRIGGER
ON DOCSADM.ACTIVITYLOG
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--Declare some variable and set it as a value of 115.
--Example:
DECLARE #AlogType int = (SELECT I.ACTIVITY_TYPE FROM DOCSADM.ACTIVITYLOG A, INSERTED I) --This is the value you are looking for regarding the DM client/Matter actitivty type.
DECLARE #AlogDesc varchar(32) = (Select i.ACTIVITY_DESC from docsadm.ACTIVITYLOG A, INSERTED I)
--Next, you should have a fork or path in your trigger to determine how it proceeds.
--Path 1: The #AlogType value matches the inserted value so you want to process the rest of the trigger. Example path – “ProcessTrigger:”
--Path 2: The #AlogType value does NOT match the inserted value, you want to exit the trigger. Example Path – “ExitTrigger:”
IF #AlogType <> 115
GOTO TriggerExit;
ELSE
Begin
/*Create first temp table to collect insert values*/ --This table will have the SysID Value and the corresponding docnumber for the items you want.
--You can add whatever other values you think you need.
CREATE TABLE #TempSet1
(
AlogsysID INT,
Docnum INT,
AlogDate Varchar(64),
AlogTypist INT,
AlogAuthor INT,
AlogDesc varchar(32),
ALOGVER varchar(10),
ALOG_MATTER INT
)
INSERT INTO #TempSet1 (AlogsysID,Docnum,AlogDate,AlogTypist,AlogAuthor, ALOG_MATTER)
--SELECT You SELECT STATEMENT WILL GO HERE MODIFIED TO POPULATE THE TABLE WITH THE DOCNUMBERS YOU WANT!!
select top 1 System_id, docnumber, LAST_ACCESS_DATE, TYPIST, AUTHOR, MATTER from docsadm.PROFILE where EXISTS (SELECT CLIENT.SYSTEM_ID FROM DOCSADM.CLIENT INNER JOIN DOCSADM.MATTER ON MATTER.CLIENT_ID = CLIENT.SYSTEM_ID
WHERE MATTER.SYSTEM_ID =#AlogDesc OR INH_LUP_SEC_FROM IS NULL OR INH_LUP_SEC_FROM = 0) AND MATTER=#AlogDesc
/*Set variable #SysID as the LASTKEY value -1. This will be used to set the SysID column on the #TempSet table*/
--DECLARE #SysID INT = (SELECT LASTKEY FROM DOCSADM.SEQ_SYSTEMKEY) -1;
/*Set the SysID value for every row on the #TempSet1 table as the #SysID variable +1*/
--UPDATE #TempSet1
--SET #SysID = AlogsysID = #SysID + 1
--Your #TempSet should now be set with ALL of the System_IDs and Docnumbers necessary for your insert!!!!—
--Verify this by doing a select against the #TempSet1 Table
SELECT * FROM #TempSet1;
--Next you need to set the SystemID to the correct value for future processing. To do this, we need to get a total count from the #TempSet table.
/*Set a variable to update the NEXTKEY value on the DOCSADM.SEQ_SYSTEMKEY table. The NEXTKEY value is used for the SYSTEM_ID field*/
--DECLARE #SeqUpdateCount INT = (SELECT COUNT(*) FROM #TempSet1);
/*Update the LASTKEY Value on the SEQ_SYSTEMKEY table to the next available value for DM.*/
--UPDATE DOCSADM.SEQ_SYSTEMKEY SET LASTKEY = LASTKEY+#SeqUpdateCount
--If you have all the values you need in your temp table, you can now insert them into the ACTIVITYLOG table.
--INSERT INTO DOCSADM.ACTIVITY
--(SYSTEM_ID, DOCNUMBER, START_DATE, version, EXT,)
--SELECT
--AlogSysID,Docnum,GETUTCDATE(),BLAH, BLAH
--FROM #TableSet1
INSERT INTO DOCSADM.ACTIVITYLOG
(SYSTEM_ID,
DOCNUMBER,
START_DATE,
TYPIST,
AUTHOR,
ACTIVITY_DESC,
VERSION_LABEL,
ACTIVITY_TYPE)
SELECT
AlogsysID, Docnum,AlogDate,AlogTypist, AlogAuthor, ALOG_MATTER, '',115
FROM #TempSet1;
--Now you need to Drop the Temp Table
DROP TABLE #TempSet1
--Go to the other half of your path above to exit the trigger.
END
TriggerExit:
END
Go
but when I try to run any INSERT statement on this table I get this error message. It doesn't matter if the activity_type has a value of 115 or not
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I know the issue is with this section of the trigger:
INSERT INTO #TempSet1 (AlogsysID,Docnum,AlogDate,AlogTypist,AlogAuthor, ALOG_MATTER)
--SELECT You SELECT STATEMENT WILL GO HERE MODIFIED TO POPULATE THE TABLE WITH THE DOCNUMBERS YOU WANT!!
SELECT TOP 1
System_id
, docnumber
, LAST_ACCESS_DATE
, TYPIST
, AUTHOR
, MATTER
FROM docsadm.PROFILE
WHERE EXISTS (SELECT CLIENT.SYSTEM_ID
FROM DOCSADM.CLIENT
INNER JOIN DOCSADM.MATTER
ON MATTER.CLIENT_ID = CLIENT.SYSTEM_ID
WHERE MATTER.SYSTEM_ID =#AlogDesc
OR INH_LUP_SEC_FROM IS NULL
OR INH_LUP_SEC_FROM = 0)
AND MATTER=#AlogDesc
It's the SELECT statement that is causing it to fail.
I know that this statement will bring back multiple rows but I only need the value from one of them so I can use this value for my INSERT. I though having the "select top 1" would do this for me but it's not working like I think it should. What am I missing?
If I had to guess I would say your problem is here:
DECLARE #AlogType int = (SELECT I.ACTIVITY_TYPE FROM DOCSADM.ACTIVITYLOG A, INSERTED I) --This is the value you are looking for regarding the DM client/Matter actitivty type.
DECLARE #AlogDesc varchar(32) = (Select i.ACTIVITY_DESC from docsadm.ACTIVITYLOG A, INSERTED I)
How are ACTIVITYLOG and INSERTED joined in the above ? without a where it would be a CROSS JOIN. Why do you even drag ACTIVITYLOG into it, you can simply use INSERTED. Also please try to stop using implicit joins ( I can see that later down the script you use the proper, more verbose join syntax)
TRY:
DECLARE #AlogType int = (SELECT I.ACTIVITY_TYPE FROM INSERTED I) --This is the value you are looking for regarding the DM client/Matter actitivty type.
DECLARE #AlogDesc varchar(32) = (Select i.ACTIVITY_DESC from INSERTED I)
Be careful that this will work with single inserts only. When you do batched inserts the INSERTED is a table containing multiple rows and you will run into issues again.
I have a SQL Trigger on a table that works... most of the time. And I cannot figure out why sometimes the fields are NULL
The trigger works by Updateing the LastUpdateTime whenever something is modified in the field, and the InsertDatetime when first Created.
For some reason this only seems to work some times.
ALTER TRIGGER [dbo].[DateTriggerTheatreListHeaders]
ON [dbo].[TheatreListHeaders]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS(SELECT * FROM DELETED)
BEGIN
UPDATE ES
SET InsertDatetime = Getdate()
,LastUpdateDateTime = Getdate()
FROM TheatreListHeaders es
JOIN Inserted I ON es.UNIQUETHEATRELISTNUMBER = I.UNIQUETHEATRELISTNUMBER
END
IF UPDATE(LastUpdateDateTime) OR UPDATE(InsertDatetime)
RETURN;
IF EXISTS (
SELECT
*
FROM
INSERTED I
JOIN
DELETED D
-- make sure to compare inserted with (same) deleted person
ON D.UNIQUETHEATRELISTNUMBER = I.UNIQUETHEATRELISTNUMBER
)
BEGIN
UPDATE ES
SET InsertDatetime = ISNULL(es.Insertdatetime,Getdate())
,LastUpdateDateTime = Getdate()
FROM TheatreListHeaders es
JOIN Inserted I ON es.UNIQUETHEATRELISTNUMBER = I.UNIQUETHEATRELISTNUMBER
END
END
A much simpler and efficient approach to do what you are trying to do, would be something like...
ALTER TRIGGER [dbo].[DateTriggerTheatreListHeaders]
ON [dbo].[TheatreListHeaders]
AFTER INSERT,UPDATE
AS
BEGIN
SET NOCOUNT ON;
--Determine if this is an INSERT OR UPDATE Action .
DECLARE #Action as char(1);
SET #Action = (CASE WHEN EXISTS(SELECT * FROM INSERTED)
AND EXISTS(SELECT * FROM DELETED)
THEN 'U' -- Set Action to Updated.
WHEN EXISTS(SELECT * FROM INSERTED)
THEN 'I' -- Set Action to Insert.
END);
UPDATE ES
SET InsertDatetime = CASE WHEN #Action = 'U'
THEN ISNULL(es.Insertdatetime,Getdate())
ELSE Getdate()
END
,LastUpdateDateTime = Getdate()
FROM TheatreListHeaders es
JOIN Inserted I ON es.UNIQUETHEATRELISTNUMBER = I.UNIQUETHEATRELISTNUMBER;
END
"If update()" is poorly defined/implemented in sql server IMO. It does not do what is implied. The function only determines if the column was set by a value in the triggering statement. For an insert, every column is implicitly (if not explicitly) assigned a value. Therefore it is not useful in an insert trigger and difficult to use in a single trigger that supports both inserts and updates. Sometimes it is better to write separate triggers.
Are you aware of recursive triggers? An insert statement will execute your trigger which updates the same table. This causes the trigger to execute again, etc. Is the (database) recursive trigger option off (which is typical) or adjust your logic to support that?
What are your expectations for the insert/update/merge statements against this table? This goes back to your requirements. Is the trigger to ignore any attempt to set the datetime columns directly and set them within the trigger always?
And lastly, what exactly does "works sometimes" actually mean? Do you have a test case that reproduces your issue. If you don't, then you can't really "fix" the logic without a specific failure case. But the above comments should give you sufficient clues. To be honest, your logic seems to be overly complicated. I'll add that it also is logically flawed in the way that it set insertdatetime to getdate if the existing value is null during an update. IMO, it should reject any update that attempts to set the value to null because that is overwriting a fact that should never change. M.Ali has provided an example that is usable but includes the created timestamp problem. Below is an example that demonstrates a different path (assuming the recursive trigger option is off). It does not include the rejection logic - which you should consider. Notice the output of the merge execution carefully.
use tempdb;
set nocount on;
go
create table zork (id integer identity(1, 1) not null primary key,
descr varchar(20) not null default('zippy'),
created datetime null, modified datetime null);
go
create trigger zorktgr on zork for insert, update as
begin
declare #rc int = ##rowcount;
if #rc = 0 return;
set nocount on;
if update(created)
select 'created column updated', #rc as rc;
else
select 'created column NOT updated', #rc as rc;
if exists (select * from deleted) -- update :: do not rely on ##rowcount
update zork set modified = getdate()
where exists (select * from inserted as ins where ins.id = zork.id);
else
update zork set created = getdate(), modified = getdate()
where exists (select * from inserted as ins where ins.id = zork.id);
end;
go
insert zork default values;
select * from zork;
insert zork (descr) values ('bonk');
select * from zork;
update zork set created = null, descr = 'upd #1' where id = 1;
select * from zork;
update zork set descr = 'upd #2' where id = 1;
select * from zork;
waitfor delay '00:00:02';
merge zork as tgt
using (select 1 as id, 'zippity' as descr union all select 5, 'who me?') as src
on tgt.id = src.id
when matched then update set descr = src.descr
when not matched then insert (descr) values (src.descr)
;
select * from zork;
go
drop table zork;
I don't know if I'm thinking correct, so I'm open for suggestions.
I'm using MS SQL SERVER 2008 R2.
Here is the 'story'
Everytime someone insert a row into tblDelivered there is a trigger that insert in tblConditionDel five values(1,1,1,1,1). This is a table with an auto ID increment. And for that inserted row must fieldname ConditionID be updated with the ID from tblConditionDel.
I think there is something wrong with my where statement
If I delete the where statement the ID is update for the entire table, but it must be for the one inserted row.
My code:
ALTER TRIGGER [dbo].[trgCond2] ON [dbo].[tblDelivered]
AFTER INSERT
AS
insert into tblConditionDel(Con1,Con2,Con3,Con4, Con5)
values(1,1,1,1,1);
update tblDelivered set ConditionID = (select max(ConditionID) from tblConditionDel)
where (select 1 from inserted) = tblDelivered.ConditionID
Thx in advance
Your solution does not work if more than one row is inserted.
Do like this
CREATE TABLE tblDelivered (
DeliveredID int NOT NULL
,ConditionID int
);
CREATE TABLE tblConditionDel (
ConditionID int IDENTITY(1,1)
,Con1 int NOT NULL
,Con2 int NOT NULL
,Con3 int NOT NULL
,Con4 int NOT NULL
,Con5 int NOT NULL
);
CREATE TRIGGER [dbo].[trgCond2] ON [dbo].[tblDelivered]
AFTER INSERT
AS
SET NOCOUNT ON;
DECLARE #ConditionIDs AS table ( -- stores inserted conditionsIDs
DeliveredID int NOT NULL
,ConditionID int NOT NULL
);
MERGE INTO tblConditionDel -- INSERT does not support OUTPUT INTO for multiple rows
USING inserted AS triggerinserted
ON 1 = 0
WHEN NOT MATCHED THEN
INSERT (Con1, Con2, Con3, Con4, Con5)
VALUES (1,1,1,1,1)
OUTPUT triggerinserted.DeliveredID
,inserted.ConditionID
INTO #ConditionIDs;
UPDATE tblDelivered
SET ConditionID = ConditionIDs.ConditionID
FROM tblDelivered
INNER JOIN #ConditionIDs AS ConditionIDs
ON ConditionIDs.DeliveredID = tblDelivered.DeliveredID
-- Test code
INSERT INTO tblDelivered (DeliveredID)
VALUES (4),(5),(6);
SELECT * FROM tblConditionDel
SELECT * FROM tblDelivered
You would want to do something like this:
ALTER TRIGGER [dbo].[trgCond2] ON [dbo].[tblDelivered]
AFTER INSERT
AS
declare #new_id int, #delivered_id int
set #delivered_id = (select ConditionID from inserted) -- captures id from inserted table
insert into tblConditionDel(Con1,Con2,Con3,Con4, Con5)
values(1,1,1,1,1);
set #new_id = scope_identity() -- captures new id from tblCondition into a variable
update tblDelivered set ConditionID = #new_id -- set new tblcondition id
where ConditionID = #delivered_id -- for the record that matches the inserted one
I am trying to write a trigger which would audit a table's every field - a row's old value and new value in a table. If any of the field has been modified, I need to save the fields old value and the new value along with field name in an audit table, as a new entry.
create trigger Trg_Institution_FieldAudit on Table1 AFTER UPDATE AS
DECLARE #OldName VARCHAR(30)
DECLARE #CurrentName VARCHAR(30)
DECLARE #OldId VARCHAR(30)
DECLARE #CurrentId VARCHAR(30)
DECLARE #modifiedBy VARCHAR(30)
If update(Name)
BEGIN
select #OldName = Name from deleted
select #CurrentName = Name from Inserted
select #OldId = ID from deleted
select #currentId = ID from Inserted
select #modifiedBy = modifiedBy from deleted
--INSERT statement for Name field alone
END;
This works fine for a small number of fields, but I have a lot of fields (more than 60), and I am not achieving the performance that is required, because of a lot of if conditions. Is there a better way of doing this? On top of this, there are concurrent updates that are happening to around 3 million records in this table, which makes a lot of things go wrong :(
EDIT: Only ONE row will get updated by an UPDATE statement
Oh my. Please avoid using a cursor whenever possible! You can easily use an insert statement with a select referencing the inserted and deleted tables. Below is a sample from one of my update triggers.
DECLARE #AuditTime DATETIME
SET #AuditTime = GetDate()
IF UPDATE([AccountManager])
INSERT INTO Audit.AuditHistory (AuditId, AuditDate, AuditTableName, EntityKey, AuditFieldName, OldValue, NewValue, FieldDisplayText, OldDisplayText, NewDisplayText, ModifiedBy)
SELECT NewId(),
#AuditTime,
'[tblOpportunity]',
cast(d.[GOTSID] AS varchar),
'[AccountManager]',
cast(d.[AccountManager] AS varchar(250)),
cast(i.[AccountManager] AS varchar(250)),
'Account Manager',
isnull(cast(d.[AccountManager] AS varchar(250)), ''),
isnull(cast(i.[AccountManager] AS varchar(250)), ''),
isnull(i.[ModifiedBy], '')
FROM deleted d
INNER JOIN inserted i ON d.GOTSID = i.GOTSID
WHERE d.[AccountManager] <> i.[AccountManager]
OR (d.[AccountManager] IS NOT NULL
AND i.AccountManager IS NULL)
OR (d.[AccountManager] IS NULL
AND i.AccountManager IS NOT NULL)
#marc_s is right, you have to re-construct your trigger and tables. here take example.
you need to put where condition in select #OldName = Name from deleted.
e.g.-
**
CREATE TRIGGER Trg_Institution_FieldAudit ON Table1 FOR UPDATE
AS
DECLARE #OldName VARCHAR(30)
DECLARE #CurrentName VARCHAR(30)
IF UPDATE (Name)
BEGIN
SET #OldName = Table1.Name FROM deleted
WHERE Table1.Name = deleted.Name;
SET #CurrentName = Table1.Name FROM inserted
WHERE Table1.Name = inserted.Name ;
--INSERT statement for old and new values.
END
GO**
After looking for an alternative for FOR EACH in SQL Server, I found that a CURSOR can be used. It serves the purpose, but need somebody to validate this.
CREATE TRIGGER Trg_Institution_FieldAudit_1 ON dbo.Institution FOR UPDATE as
-- DECLARE Variables
DECLARE institution_cursor CURSOR DYNAMIC FOR SELECT * FROM DELETED
OPEN institution_cursor FETCH NEXT FROM institution_cursor INTO -- #variables here
WHILE (##FETCH_STATUS = 0)
BEGIN
IF UPDATE(COL1)
BEGIN
INSERT INTO AuditTable VALUES (COL1, #prev, #next);
END;
FETCH NEXT FROM institution_cursor INTO -- #Variables here
END
CLOSE institution_cursor
DEALLOCATE institution_cursor
Strange situation
In a trigger i assign a column value to variable but gives exception while inserting into other table using that variable.
e.g
select #srNO=A.SrNo from A where id=123;
insert into B (SRNO) values (#srNo) // here it gives null
I run above select query in query pane it works fine but in trigger it gives me null
any suggestions
ALTER PROCEDURE ProcessData
#Id decimal(38,0),
#XMLString varchar(1000),
#Phone varchar(20)
AS
DECLARE
#idoc int,
#iError int,
#Serial varchar(15),
#PhoneNumber varchar(15),
BEGIN
COMMIT TRAN
EXEC sp_xml_preparedocument #idoc OUTPUT,#XMLString<br/>
SELECT #iError = ##Error<br/>
IF #iError = 0<br/>
BEGIN<br/>
SELECT #Serial = convert(text,[text]) FROM OPENXML (#idoc,'',1) where nodetype = 3 and ParentId = 2
IF #Serial=Valid <br/>
BEGIN<br/>
BEGIN TRAN INVALID<br/>
begin try <br/>
Declare #phoneId decimal(38,0);<br/>
SELECT #phoneId = B.phoneId FROM A
INNER JOIN B ON A.Id = B.Id WHERE A.PhoneNumber like '%'+#SenderPhone + '%'<br/>
print #phoneId ; //gives null<br/>
end try<br/>
begin catch<br/>
print Error_Message();<br/>
end catch<br/>
you should work with sets of rows in triggers, so if multiple rows are affected your code handles all rows. This will only INSERT when the value is not null:
INSERT INTO B (SRNO)
SELECT A.SrNo FROM A where id=123 AND A.SrNo IS NOT NULL
Neo, are you sure, that SELECT SrNo FROM A WHERE id = 123 returns data?
I mean, value of #srNo will not change (therefore, remain NULL) if there no records with id = 123
When you eliminate the impossible, whatever remains, however improbable, must be the truth.
The obvious answer is that at the time the trigger fires, SrNo is null or Id 123 does not exist. Is this for an insert trigger and is it the case that you are trying to take something that was just inserted into table A and push it into table B? If so, you should query against the inserted table:
//from an insert trigger on the table `A`
Insert B( SRNO )
Select SRNO
From inserted
Where Id = 123
If this is not the case, then we'd need to see the details of the Trigger itself.
solved it there is some error in xml string reading function
e.g in openxml pattern matching
Thanks all of you for help... :)