Trouble creating SQL Server 2012 trigger - sql-server

I'm quite new at SQL Server 2012, and I'm having a strange problem.
I've developed an AFTER UPDATE trigger on a table in my database. I created the trigger in our development environment which is an express edition of SQL Server 2012, no problem.
Now I have to create the same trigger in our production environment which is SQL Server 2012 Enterprise edition, and the creation script never stops executing, and the trigger is not created.
Any ideas on what I need to do to create the trigger?
The script :
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter TRIGGER [dbo].[til_aks_ved_betaling]
ON [dbo].[betalingsOplysningerbo]
AFTER UPDATE
AS
BEGIN
declare #snr uniqueidentifier
declare ##status varchar(1024)
SET NOCOUNT ON;
select
#snr = indmeldelse_snr
from
inserted
if UPDATE(betalingsDato)
begin
set ##status = 'Kalder med snr = ' + convert(varchar(38), #snr)
exec xp_logevent 60000, ##status , informational
exec overfoer_betalingsdato #snr
end
END

Try something like this....
ALTER TRIGGER [dbo].[til_aks_ved_betaling]
ON [dbo].[betalingsOplysningerbo]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
declare #snr VARCHAR(1000);
declare #status varchar(1024);
DECLARE #Temp TABLE (indmeldelse_snr uniqueidentifier , [Status] varchar(1024))
INSERT INTO #Temp (indmeldelse_snr , [Status])
SELECT i.indmeldelse_snr , i.[Status]
FROM inserted i INNER JOIN deleted d
ON i.Snr = d.Snr AND i.betalingsDato <> d.betalingsDato
WHILE EXISTS(SELECT * FROM #Temp)
BEGIN
SELECT TOP 1 #snr = 'Kalder med snr = ' + convert(varchar(38),indmeldelse_snr )
,#status = [Status]
FROM #Temp
exec xp_logevent 60000, #status , informational
exec overfoer_betalingsdato #snr
DELETE FROM #Temp WHERE indmeldelse_snr = #snr
END
END

2 things here, common for new people, an UPDATE is a DELETE and an INSERT so make sure you have both before you assume it is an update. Second, these special tables will return all the rows affect by a single sql call. For example, Update Table SET This = 'That' will update every record in the table leaving INSERTED with MANY records.

Related

Fire SQL Trigger When Column Value Changes

I am adding the date to a column in SQL when the 'workstatus' is 'completed', but my problem is, when I open and save the same job again in the software, it runs the trigger and changes the date again to a new value which I don't want.
I want the trigger to run only if the 'workstatus' value is something else than 'completed'.
GO
/****** Object: Trigger [dbo].[TRJCD_JOBREQUEST] Script Date: 06/25/2021 15:49:04 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[TRJCD_JOBREQUEST] ON [dbo].[TBL_JOBREQUEST]
AFTER UPDATE,INSERT
AS
if (Update (workstatus))
begin
DECLARE #Jobcompletiondate datetime
DECLARE #workstatus VARCHAR(15)
DECLARE #jobid int
select #workstatus = workstatus from inserted
select #jobid = jobid from inserted
select #Jobcompletiondate = GETDATE()
begin
if #workstatus='Completed'
update TBL_JOBREQUEST set JobCompDate=#Jobcompletiondate where jobid = #jobid
end
end
The following is how you should construct your trigger.
There is no need to assign any values to variables, triggers fire once per batch and always operate on the set of updated rows.
If you update a status to Completed you need to check it's not currently Completed, also if you want to retain the first JobCompDate even if the status is amended afterwards simply use a case expression to only update the column where it's currently NULL.
create or alter trigger [dbo].[TRJCD_JOBREQUEST] on [dbo].[TBL_JOBREQUEST]
after update,insert
as
if ##RowCount=0 return
set nocount on
if Update (workstatus)
begin
update t set
t.JobCompDate=case when t.JobCompDate is null then GetDate() else t.JobCompDate end
from inserted i join TBL_JOBREQUEST t on t.jobid=i.jobid
where i.workstatus='Completed'
and not exists (
select * from deleted d
where d.jobid=i.jobid and d.workstatus=i.workstatus
)
end
Please note that I do not have your data set, so I'm unable to test the trigger, however, based on what you provided in your question, I believe this is the answer you are seeking:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[TRJCD_JOBREQUEST] ON [dbo].[TBL_JOBREQUEST]
AFTER UPDATE,INSERT
AS
if (Update (workstatus))
begin
DECLARE #Jobcompletiondate datetime
DECLARE #currentworkstatus VARCHAR(15)
DECLARE #oldworkstatus VARCHAR(15)
DECLARE #jobid int
select #oldworkstatus = workstatus from deleted
select #currentworkstatus = workstatus from inserted
select #jobid = jobid from inserted
select #Jobcompletiondate = GETDATE()
begin
if #currentworkstatus='Completed' and #oldworkstatus <> 'Completed'
update TBL_JOBREQUEST set JobCompDate=#Jobcompletiondate where jobid = #jobid
end
end
You needed to check if the deleted workstatus does not equal Completed and only then should the trigger fire.

TempDB caching issues with SQL Server 2019

I have a problem that works in SQL Server 2017 but not in SQL Server 2019. It is related to tempdb caching. This has to do with creating temporary tables in stored procedures and changing its structure using dynamic SQL. We have a need to do that for various dynamic reporting needs. The first time it is called, the structure is cached and subsequent call to the procedure fails or returns invalid results. How do I prevent caching of such tables? Below is some sample code and how come it works in 2017. Help appreciated.
CREATE PROCEDURE [dbo].[tempDBCachingCheck]
#yearList varchar(max)
AS
BEGIN
SET NOCOUNT ON
DECLARE #yearCount int
DECLARE #yearCounter INT
DECLARE #yearValue INT
DECLARE #sql nvarchar(max)
-- With table variable
DECLARE #tempYearList TABLE (id INT IDENTITY(1,1), rpt_yr int)
INSERT INTO #tempYearList (rpt_yr)
SELECT value FROM STRING_SPLIT(#yearList, ',');
SELECT * FROM #tempYearList
--------------------------------------------------------------------
--With temporary table, since we will be altering this with dynamic sql
CREATE TABLE #returnTable (id INT IDENTITY(1,1))
-- Tried adding a named constraint to not make it cache, but does not work
ALTER TABLE #returnTable
ADD CONSTRAINT UC_ID UNIQUE (id);
SELECT #yearCount = COUNT(*) FROM #tempYearList
-- Add the years as columns to the return table to demostrate the problem
SET #sql = N'ALTER TABLE #returnTable ADD '
SET #yearCounter = 1
WHILE #yearCounter <= #yearCount
BEGIN
SELECT #yearValue = rpt_yr FROM #tempYearList WHERE id = #yearCounter
IF #yearCounter > 1
SET #Sql = #Sql + N', '
SET #sql = #sql + N' [' + convert(varchar(20), #yearValue) + N'] float'
SET #yearCounter = #yearCounter + 1
END
EXECUTE sp_executesql #sql
SELECT * FROM #returnTable
-- No need to drop the temporary tables but doing just in case
DROP TABLE #returnTable
END
GO
-- run these statements and you will see the second call with return the cached #returnTable
EXEC tempDBCachingCheck '2019,2020'
EXEC tempDBCachingCheck '2017,2018,2019,2020'
GO
-- Clear temp table cache and call in reverse order, then will hit an error
-- 'A severe error occurred on the current command. The results, if any, should be discarded.'
USE tempDB
GO
DBCC FREEPROCCACHE
GO
EXEC tempDBCachingCheck '2017,2018,2019,2020'
EXEC tempDBCachingCheck '2019,2020'
GO
It seems this has been fixed in one of cummulative update. The description seems to match:
KB4538853:
When you repeatedly run a stored procedure that uses temporary table with indexes on SQL Server 2019, the client may receive an unexpected error with message "A severe error occurred on the current command" and an access violation exception is recorded on the SQL Server. If the same workload is executed on any previous major version of SQL Server, this issue does not occur.
Dan Guzman's recommendation to install newest CU is the way to go.
Using: EXEC tempDBCachingCheck '2017,2018,2019,2020' WITH RECOMPILE could help as well.

Disabling Index operations for certain tables in SQL Server 2008 R2 other than DDL trigger

Is there a way to disable certian index DDL operation (create, drop and alter index) for a list of tables in MS SQL Server 2008 R2?
What I was trying to do is to create a DDL trigger that catch these events and roll them back, but it seems that all ddl trigers are after triggers and if table is very large this cause performance issues.
The trigger I am currently using is the following:
CREATE TRIGGER index_guard
ON DATABASE
FOR CREATE_INDEX, DROP_INDEX, ALTER_INDEX
AS
DECLARE #object_name NVARCHAR(50);
DECLARE #table_name NVARCHAR(50);
DECLARE #target_object_type NVARCHAR(20);
DECLARE #object_type NVARCHAR(20);
DECLARE #lookup_value NVARCHAR(100);
DECLARE #protected_indexes TABLE (Name NVARCHAR(50))
INSERT INTO #protected_indexes
SELECT Name FROM (VALUES ('TABLE1/IX_IdName'), ('TABLE2/IX_NameId')) AS tbl(Name)
SELECT #object_name = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','nvarchar(max)');
SELECT #table_name = EVENTDATA().value('(/EVENT_INSTANCE/TargetObjectName)[1]','nvarchar(max)');
SELECT #target_object_type = EVENTDATA().value('(/EVENT_INSTANCE/TargetObjectType)[1]','nvarchar(max)');
SELECT #object_type = EVENTDATA().value('(/EVENT_INSTANCE/ObjectType)[1]','nvarchar(max)');
IF #object_type = 'INDEX' AND #target_object_type = 'TABLE'
BEGIN
SET #lookup_value = #table_name + '/' + #object_name
IF EXISTS (SELECT 1 FROM #protected_indexes A WHERE A.Name = #lookup_value)
BEGIN
ROLLBACK
END
END

Sp to sync two tables using linked servers sql server

I'm working in a SP and I got two tables in different servers, one is the main and the other is a copy but whit less columns, all I want is to run the SP every 5 min over the main table in order to validate if new records has been created, if yes take those new records and insert them into the copy table, that resides in the other server.
Searching a solution I've found this script wich works ok in the same server, but when I try to run it with the linked server it fails....please somebody help me with this.
This is the error that a get....
OLE DB provider "SQLNCLI" for linked server "ESDBCGW001T" returned
message "The partner transaction manager has disabled its support for
remote/network transactions.". Msg 7391, Level 16, State 2, Procedure
sp_newrecords, Line 37 The operation could not be performed because
OLE DB provider "SQLNCLI" for linked server "LINKEDSERVER" was unable
to begin a distributed transaction.
All configurations are perfect, and when I run the insert without the variables runs fine,I mean, instead of #val1, #val2 and #val3 I use real values 1, 'A', 'B'.
USE [XXX]
GO
/****** Object: StoredProcedure [dbo].[sp_newrecords] Script Date: 03/02/2015 11:11:57 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <>
-- Create date: <>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[sp_newrecords]
-- Add the parameters for the stored procedure here
AS
BEGIN
DECLARE #val1 int
DECLARE #val2 nvarchar(50)
DECLARE #val3 nvarchar(50)
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE mycur1 CURSOR for
select empid,fname,lname from employee
where empid = 508 --this is for test only
OPEN mycur1
FETCH NEXT FROM mycur1 INTO #val1, #val2 , #val3
WHILE ##Fetch_Status = 0
BEGIN
begin tran /* default read committed isolation level is fine */
if not exists (select * from openquery (linkedserver,'select * from DBNAME.dbo.Employee_backup'))
--insert employee_backup values (#val1, #val2 , #val3)
begin
INSERT into [linkedserver].[DBNAME].[dbo].[Employee_backup] values (#val1, #val2 , #val3)
end
/*if not exists (select * from employee_backup with (updlock, rowlock, holdlock)
where employee_backup.empid = #val1
and employee_backup.fname = #val2 )
--insert employee_backup values (#val1, #val2 , #val3)
INSERT [LINKEDSERVER].[DBNAME].[dbo].[Employee_backup] values (#val1, #val2 , #val3)*/
--else
-- /* update */
commit /* locks are released here */
FETCH NEXT FROM mycur1 INTO #val1, #val2 , #val3`enter code here`
END
CLOSE mycur1
DEALLOCATE mycur1
END
Your database admin would need to allow that permission on the target server. Personally, I would simply replicate the table from one server to the other and then the stored procedure would run against the replicated data.
If you absolutely need to go cross server, please refer to this SO question.
why not just use replication for something like this?
Might need to enable Distributed Transaction Coordinator (DTC) for your specific problem https://technet.microsoft.com/en-us/library/cc759136%28v=ws.10%29.aspx
In addition to ensuring DTC is enabled, you should be using begin distributed tran rather than begin tran
See:
https://msdn.microsoft.com/en-us/library/ms188386.aspx

How to determine if insert or update

Whenever INSERT is happened in the CUSTOMER table,I need to call the "StoredProcedure1"and
UPDATE is happend in the CUSTOMER table,I need to call the "StoredProcedure2" in the Trigger.
How to determine if insert or update in the trigger from SQL Server 2008.
Some one can please help me how to solve?
Code:
CREATE TRIGGER Notifications ON CUSTOMER
FOR INSERT,UPDATE
AS
BEGIN
DECLARE #recordId varchar(20);
set #recordId= new.Id;
//if trigger is insert at the time I call to SP1
EXEC StoredProcedure1 #recordId
//if trigger is Upadeted at the time I call to SP2
EXEC StoredProcedure2 #recordId
END
Let SQL Server be SQL Server, and have it do the work for you!
Create separate triggers for each change event (insert,update and/or delete).
Put the logic for each into the trigger that needs it.
No need to have to check for the event type.
And don't call a procedure unless it is quick, fast, and can't block others.
The easiest way to solve this problem would be to have two triggers, one for the insert and one for the update.
CREATE TRIGGER InsertNotifications ON CUSTOMER
FOR INSERT
AS
BEGIN
DECLARE #recordId varchar(20);
set #recordId= new.Id;
//if trigger is insert at the time I call to SP1
EXEC StoredProcedure1 #recordId
END
CREATE TRIGGER UpdateNotifications ON CUSTOMER
FOR UPDATE
AS
BEGIN
DECLARE #recordId varchar(20);
set #recordId= new.Id;
//if trigger is Upadeted at the time I call to SP2
EXEC StoredProcedure2 #recordId
END
Try this code for trigger for INSERT, UPDATE and DELETE. This works fine on Microsoft SQL SERVER 2008
if (Select Count(*) From inserted) > 0 and (Select Count(*) From deleted) = 0
begin
print ('Insert...')
end
if (Select Count(*) From inserted) = 0 and (Select Count(*) From deleted) > 0
begin
print ('Delete...')
end
if (Select Count(*) From inserted) > 0 and (Select Count(*) From deleted) > 0
begin
print ('Update...')
end
On an INSERT, the virtual DELETED table will be empty.
create or replace trigger comp
before
insert or delete or update
on student
referencing old as o new as n
for each row
begin
if deleting then
insert into student_backup values
(:o.studid,:o.studentname,:o.address,:o.contact_no,:o.branch,sysdate);
end if;
if inserting then
insert into student_backup values
(:n.studid,:n.studentname,:n.address,:n.contact_no,:n.branch,sysdate);
end if;
if updating then
insert into student_backup values
(:o.studid,:o.studentname,:o.address,:o.contact_no,:o.branch,sysdate);
end if;
end comp;

Resources