Trigger After Update for a Specific Value - sql-server

Is it possible to create a trigger on SQL Server that will execute when a column value is updated to a specific value. How can I do this?

Try with following
CREATE TRIGGER trgAfterUpdate ON [dbo].[Employee_Test]
FOR UPDATE
AS
declare #empid int;
declare #empname varchar(100);
declare #empsal decimal(10,2);
declare #audit_action varchar(100);
select #empid=i.Emp_ID from inserted i;
select #empname=i.Emp_Name from inserted i;
select #empsal=i.Emp_Sal from inserted i;
if update(Emp_Name)
set #audit_action='Updated Record -- After Update Trigger.';
if update(Emp_Sal)
set #audit_action='Updated Record -- After Update Trigger.';
insert into Employee_Test_Audit(Emp_ID,Emp_Name,Emp_Sal,Audit_Action,Audit_Timestamp)
values(#empid,#empname,#empsal,#audit_action,getdate());
PRINT 'AFTER UPDATE Trigger fired.'
GO

I write a simple trigger and hoping that it helps you.
CREATE TRIGGER [FUND].[TRU_FUND_FUND_PRICE] ON [FUND].[FUND_PRICE]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #PRICE_ID BIGINT
DECLARE #UNIT_PRICE DECIMAL(18,7)
DECLARE #UNIT_PRICE_BEFORE_UPDATE DECIMAL(18,7)
DECLARE #TOTAL_SHARE_BEFORE_UPDATE DECIMAL(18,7)
DECLARE #TOTAL_SHARE DECIMAL(18,7)
DECLARE #RECORD_STATUS_BEFORE_UPDATE CHAR(1)
DECLARE #RECORD_STATUS CHAR(1)
SELECT #UNIT_PRICE_BEFORE_UPDATE=UNIT_PRICE , #TOTAL_SHARE_BEFORE_UPDATE = TOTAL_SHARE, #RECORD_STATUS_BEFORE_UPDATE =RECORD_STATUS FROM DELETED
SELECT #PRICE_ID = PRICE_ID,#UNIT_PRICE=UNIT_PRICE,#TOTAL_SHARE=TOTAL_SHARE,#RECORD_STATUS=RECORD_STATUS FROM INSERTED
--You can compare to specific values instead of deleted data
IF #UNIT_PRICE=#UNIT_PRICE_BEFORE_UPDATE AND #TOTAL_SHARE =#TOTAL_SHARE_BEFORE_UPDATE AND #RECORD_STATUS_BEFORE_UPDATE = #RECORD_STATUS
BEGIN
RETURN
END
INSERT INTO FUND.FUND_PRICE_LOG (
[PRICE_ID],
[FUND_ID],
[PRICE_DATE],
[UNIT_PRICE],
[UPDATE_USER_CODE],
[UPDATE_PROG_CODE],
[UPDATE_DATE],
[OPERATION],
[RECORD_STATUS],
[TOTAL_SHARE],
[LIMIT_CHANGE_AMOUNT]
)
SELECT [PRICE_ID], [FUND_ID], [PRICE_DATE],
[UNIT_PRICE],
[UPDATE_USER_CODE],
[UPDATE_PROG_CODE],
GETDATE(),
'U',
[RECORD_STATUS],
[TOTAL_SHARE] ,
([TOTAL_SHARE] - #TOTAL_SHARE_BEFORE_UPDATE)
FROM INSERTED
END
GO

Related

SQL server execute SP from sql table and update

The table below stores sql insert statements and I run those from a sp. I need to also add an insert to the last_run_dt column. I put the code together via existing stackoverflow questions. I need help implementing this in my code, any feedback will be helpful.
How can I update my code to update the last_run_dt column?
Table:
audit_sql_id audit_sql last_run_dt
1 select * from <<need to add last run_dt value>>
2 select * from <<need to add last run_dt value>>
Code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter proc [dbo].[sp_sqlAudit]
#packagename as varchar(255)
as
begin
set nocount on;
if #packagename='SQL_DM_AUDIT'
begin
declare #queries table (audit_sql_id int identity(1,1),sqlscript varchar(max))
declare #str_query varchar(max);
declare #startloop int
declare #endloop int
insert into #queries
select audit_sql
from dw.dbo.audit_sql with(nolock)
select #endloop = max(audit_sql_id), #startloop = min(audit_sql_id)
from #queries
while #startloop < = #endloop
begin
select #str_query = sqlscript
from #queries
where audit_sql_id = #startloop
exec (#str_query)
set #startloop = #startloop + 1
end
end
end
I would suggest a slight refactor something like the below. There's no need to bring the entire list of sql statements into TemDB, just iterate over it and get each statement in turn. I would also always add a #debug parameter to print the sql instead if executing.
create or alter procedure dbo.sqlAudit
#packagename as varchar(255)
as
set nocount on;
declare #str_query varchar(max), #Id int
declare #AuditID table (Id int)
if #packagename='SQL_DM_AUDIT'
begin
insert into #AuditID (Id) /* Get list of IDs */
select audit_sql_id
from dw.dbo.audit_sql
while exists(select * from #AuditID) /* Continue while there are IDs in the list */
begin
select top (1) #Id=Id from #AuditID /* Get an ID */
select #str_query=audit_sql /* Get the sql for the ID */
from dw.dbo.audit_sql
where audit_sql_id=#Id
delete from #AuditID where Id=#Id /* Remove this ID from the list */
begin try
exec (#str_query)
if ##Error=0
begin
update dw.dbo.audit_sql set last_run_dt=GetDate() /* Update date for ID if run successful */
where audit_sql_id=#Id
end
end try
begin catch
/*handle error*/
end catch
end
end
go

Insert trigger: set value from procedure ends with 3609 error

I have to check if a specific value of an insert is null. If it is null, I want to give it a value from a stored procedure. This procedure returns a number like a sequence, but because I have SQL Server 2008 I had to create it myself:
CREATE PROCEDURE dbo.Get_BAV_PERSONALARCHIV_SEQUENCE ( #value BIGINT OUTPUT)
AS
BEGIN TRANSACTION;
INSERT dbo.BAV_Personalarchiv_Sequence WITH (TABLOCKX) DEFAULT VALUES;
ROLLBACK TRANSACTION;
SELECT #value = SCOPE_IDENTITY();
GO
I want to use the created value in my Insert Trigger if 'SYSROWID' is null (if it is null, it should be the only record with it) :
ALTER TRIGGER [dbo].[NT_BAV_PERSONALARCHIV_MITARBEITER_INSERT]
ON [dbo].[NT_BAV_PERSONALARCHIV_MITARBEITER]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
If (SELECT SYSROWID FROM INSERTED) IS NULL
Begin
DECLARE #value BIGINT;
EXECUTE dbo.Get_BAV_PERSONALARCHIV_SEQUENCE #value OUTPUT;
Update dbo.NT_BAV_PERSONALARCHIV_MITARBEITER
SET SYSROWID = #value
where SYSROWID IS NULL
End
END
But sadly it returns with an 3609 error and rolls back the transaction.
Testing only the Execute and Update works without a problem:
DECLARE #value BIGINT;
EXECUTE dbo.Get_BAV_PERSONALARCHIV_SEQUENCE #value OUTPUT;
Update dbo.NT_BAV_PERSONALARCHIV_MITARBEITER
SET SYSROWID = #value
where SYSROWID IS NULL
What am I missing? Thank you for your help!
Ok, I found out that the rollback in the procedure causes the trigger to end with the error. My workaround is to delete the values of the "sequence"-table before I create a new value:
ALTER PROCEDURE dbo.Get_BAV_PERSONALARCHIV_SEQUENCE ( #value BIGINT OUTPUT)
AS
delete from dbo.BAV_Personalarchiv_Sequence
INSERT dbo.BAV_Personalarchiv_Sequence WITH (TABLOCKX) DEFAULT VALUES;
SELECT #value = SCOPE_IDENTITY();
GO

Invalid Object Name #tablename at second call of #tablename sql server 2005

When I execute the code :
declare #result int
exec recostcos #result
select #result
I get 'Msg 208, Level 16, State 0, Procedure RecostCOS, Line 138
Invalid object name '#rLB'.'
The strange thing is The first reference to #rLB did not produce any error but the second reference on line 138 produces the error above.
Please find below the code for recostcos :
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[RecostCOS](#result int output)
as
BEGIN TRY
BEGIN TRANSACTION
SET NOCOUNT ON
--variables
declare #itemName varchar(50)
declare #invoiceNo varchar(50)
declare #customerName varchar(100)
declare #recordedBy varchar(100)
declare #transDate datetime
declare #supCode varchar(50)
declare #decemQty1 decimal(18,6)
declare #decemQty2 decimal(18,6)
declare #decemQty3 decimal(18,6)
declare #recostQty decimal(18,6)
declare #count int
declare #innerCount int
declare #outputCode int
declare #outputCounter int
declare #recId int
declare #innerId int
create table #supcodes(supcode varchar(50),item_name varchar(50),
qty decimal(18,6),id int identity(1,1))
create table #recostList(invoice_no varchar(50),qty decimal(18,6), id int identity(1,1))
create table #rLB(invc_no varchar(50),qty decimal(18,6), id int identity(1,1))
--check for supplyCode needing reprocessing
select #count=count(*) from someTable where recosted=0;
if(#count<=0)
begin
commit
set #result=0
return #result
end
--
insert into #supcodes(supcode,item_name,qty)
select supply_code,item_name,quantity from someTable
where recosted=0
--recost each supply code needing recosting
while(#count>0)
begin
select top 1 #supCode=supcode,#itemName=item_name,#decemQty1=qty,#recId=id
from #supcodes
select #decemQty2=sum(current_qty) from someTable2 where item_name=#itemName
select #decemQty3=quantity from someTable3 where item_name=#itemName
if(#decemQty2 is null)
set #decemQty2=0
if(#decemQty3 is null)
set #decemQty3=0
--debug
if(#decemQty2<>#decemQty3)
begin
--check if there is a log of this error
select #count=count(*) from someTable4 where error_code=1 and
item_name=#itemName and supply_code=#supCode and resolved=0
if(#count<=0)
--error in stock quantities (this must be resolved b4 any recosting)
insert into someTable4(supply_code,item_name,error_code,error_source,error_detail)
values(#supCode,#itemName,1,'re-costing','Mismatch in stock quantities in stock state and supply codes tables')
end
else if(#decemQty1>#decemQty2)
begin
--check if there is a log of this error
select #count=count(*) from someTable4 where error_code=2 and
item_name=#itemName and supply_code=#supCode and resolved=0
--insufficient stock for recosting
if(#count<=0)
insert into someTable4(supply_code,item_name,error_code,error_source,error_detail)
values(#supCode,#itemName,2,'re-costing','insufficient stock for recosting')
end
else
begin
--recost cost of sales of item involved
--get list of invoices of item to be recosted
set #recostQty=#decemQty1
insert into #recostList(invoice_no,qty)
select invoice_no,quantity from someTable5
where supply_code=#supCode and item_name=#itemName
insert into #rLB(invc_no,qty) select invoice_no,qty from #recostList
--delete cost of sales relating to supcod and item in stock account
select #innerCount=count(*) from #recostList
while(#innerCount>0)
begin
select top 1 #invoiceNo=invoice_no,#decemQty2=qty,#innerId=id
from #recostList
delete someTable6 where description
like 'sales of '+ltrim(rtrim(convert(varchar(20),#decemQty2)))+'%'+
#itemName+'%'+#invoiceNo
delete someTable5 where supply_code=#supCode and item_name=#itemName
and quantity=#decemQty2
delete #recostList where id=#innerId
set #innerCount=#innerCount-1
end
--call costByFIFO to recost item
select #innerCount=count(*) from #rLB
set #outputCounter=#innerCount
while(#innerCount>0)
begin
select top 1 #invoiceNo=invc_no,#decemQty2=qty,#innerId=id
from #rLB
select #customerName=customer_name, #transDate=trans_date,
#recordedBy=recorded_by from someTable7 where invoice_no=#invoiceNo
exec #outputCode=costByFIFO #itemName,#invoiceNo,#customerName,
#decemQty2,#transDate,#recordedBy
--ensure each invoice is costed or reverse entire process
if(#outputCounter=0)
begin
set #outputCounter=#outputCounter-1
end
else
begin
set #result=3 --failed to cost all invoices involved
rollback
end
delete #rLB where id=#innerId
set #innerCount=#innerCount-1
end
--outputCounter must be 0 to indicate all invoices where costed
if(#outputCounter<>0)
begin
set #result=3 --failed to cost all invoices involved
rollback
end
else
begin
update someTable set recosted=1 where supply_code=#supCode
and item_name=#itemName
end
end
delete #supcodes where id=#recId
set #count=#count-1
end
SET NOCOUNT OFF
drop table #supcodes
drop table #recostList
drop table #rLB
set #result=0
COMMIT
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() ErrorNBR, ERROR_SEVERITY() Severity,
ERROR_LINE () ErrorLine, ERROR_MESSAGE() Msg
set #result=2 --unexpected error occured
ROLLBACK
END CATCH

sql trigger cannot insert row using variable

When i use this code it inserts row
create trigger [dbo].[InsertInvPayment] on dbo.LG_001_01_PAYTRANS
after update
as
begin
SET NOCOUNT ON;
declare #InvLogicalRef int;
declare #InvNumber varchar(50);
select #InvLogicalRef = inserted.FICHEREF from inserted
select #InvNumber = dbo.LG_001_01_INVOICE.DOCODE from dbo.LG_001_01_INVOICE where dbo.LG_001_01_INVOICE.LOGICALREF = #InvLogicalRef
insert into dbo.CRMINVPAYMENT(INVNUMBER) values('Hello')
end
if i change it like this
create trigger [dbo].[InsertInvPayment] on dbo.LG_001_01_PAYTRANS
after update
as
begin
SET NOCOUNT ON;
declare #InvLogicalRef int;
declare #InvNumber varchar(50);
select #InvLogicalRef = inserted.FICHEREF from inserted
select #InvNumber = dbo.LG_001_01_INVOICE.DOCODE from dbo.LG_001_01_INVOICE where dbo.LG_001_01_INVOICE.LOGICALREF = #InvLogicalRef
insert into dbo.CRMINVPAYMENT(INVNUMBER) values(#InvNumber)
end
it doesn't work. i couldn't find a mistake in the second
Seems like You are missing the source for select InvLogicalRef. It should be
select #InvLogicalRef = inserted.FICHEREF from inserted
Also with this trigger you are assuming that only one record will update at once. This will fail for bulk updates.
The line where you assign a value to #InvLogicalRef is incomplete.
As that variable doesn't contain a value, #InvNumber can't be assigned its value and you are therefore trying to insert a NULL string into CRMINVPAYMENT.
Make sure you select the value of #InvLogicalRef from the inserted table.

SQL Server stored procedure avoid cursor

I have the following SQL Server stored procedure :
BEGIN TRAN
CREATE TABLE #TempTable (
SampleOrderID int,
SampleOrderNo varchar(512),
ChallanNoAndChallanDate varchar(MAX)
)
CREATE NONCLUSTERED INDEX #IX_Temp2_1 ON #TempTable(SampleOrderID)
DECLARE
#SQL as varchar(MAX)
SET #SQL=' SELECT SampleOrderID, SampleOrderNo FROM SampleOrder WHERE SampleOrderID IN (37808,37805,37767,37571,37745,37772,37843,37394,37909,37905,37903) '
INSERT INTO #TempTable (SampleOrderID, SampleOrderNo)
EXEC (#SQL)
DECLARE
#SampleOrderID as int,
#ChallanNoAndChallanDate as varchar(max)
DECLARE Cur_AB1 CURSOR GLOBAL FORWARD_ONLY KEYSET FOR
SELECT SampleOrderID FROM #TempTable
OPEN Cur_AB1
FETCH NEXT FROM Cur_AB1 INTO #SampleOrderID
WHILE(##Fetch_Status <> -1)
BEGIN--2
SET #ChallanNoAndChallanDate=''
SELECT #ChallanNoAndChallanDate= COALESCE(#ChallanNoAndChallanDate+ ',', '') + CONVERT(VARCHAR(12),ChallanDate,106)+':'+ChallanNo FROM Challan WHERE OrderID =#SampleOrderID AND OrderType=2
UPDATE #TempTable SET ChallanNoAndChallanDate=#ChallanNoAndChallanDate WHERE SampleOrderID=#SampleOrderID
FETCH NEXT FROM Cur_AB1 INTO #SampleOrderID
END--2
CLOSE Cur_AB1
DEALLOCATE Cur_AB1
SELECT * FROM #TempTable
DROP TABLE #TempTable
COMMIT TRAN
Output :
SamID SamNo ChallanNoAndDaet
37394 37394 ,31 May 2012:151592
37571 37571 ,31 May 2012:151580
37745 37745 ,31 May 2012:151582
37767 37767 ,30 May 2012:151507,31 May 2012:151576
37772 37772 ,31 May 2012:151587
37805 37805 ,31 May 2012:151574
37808 37808 ,31 May 2012:151573
37843 37843 ,31 May 2012:151588
37903 37903 ,31 May 2012:151597
37905 37905 ,31 May 2012:151596
37909 37909 ,31 May 2012:151593
It works successfully for small volume of data but When i try to execute it on a Large volume (i.e. more then 500,000 record) my C# interface throws the time out exception.
Can anyone help me edit my stored procedure to avoid the cursor?
Thanks for response.
I use this to avoid cursor in everywhere I need
DECLARE #num_rows int
DECLARE #cnt int
DECLARE #selected int
DECLARE #table1 TABLE (Id int not null primary key identity(1,1), col1 int )
INSERT into #table1 (col1) SELECT col1 FROM table2
SET #num_rows=##ROWCOUNT
SET #cnt=0
WHILE #cnt<#num_rows
BEGIN
SET #cnt=#cnt+1
SELECT
#selected=col1
FROM #table1
WHERE Id=#cnt
--do your stuff here--
END
I usually use something like the following:
SELECT #SampleOrderID = MIN (SampleOrderID) FROM #TempTable
WHILE #SampleOrderID IS NOT NULL
BEGIN
SET #ChallanNoAndChallanDate=''
SELECT #ChallanNoAndChallanDate= COALESCE(#ChallanNoAndChallanDate+ ',', '') + CONVERT(VARCHAR(12),ChallanDate,106)+':'+ChallanNo FROM Challan WHERE OrderID =#SampleOrderID AND OrderType=2
UPDATE #TempTable SET ChallanNoAndChallanDate=#ChallanNoAndChallanDate WHERE SampleOrderID=#SampleOrderID
SELECT #SampleOrderID = MIN (SampleOrderID) FROM #TempTable WHERE SampleOrderID > #SampleOrderID
END
This code would replace the cursor stuff you have.

Resources