Copy Trigger stops row being inserted - sql-server

I am trying to create a trigger that copies newly inserted data from one table and inserts it into another table in a linked server.
However, when the trigger is created it stops the data appearing in the original table until the trigger is deleted and also does not even copy it over to the other table in the linked server either.
Here is my trigger
GO /****** Object: Trigger [dbo].[CopyTMSINFO] Script Date: 12/07/2022 12:53:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[CopyTMSINFO]
ON [dbo].[d_iface_att]
After INSERT
AS DECLARE #EmpID nvarchar(MAX),
#datetime datetime
SELECT #EmpID = ins.emp_id FROM INSERTED ins;
SELECT #datetime = ins.date_and_time FROM INSERTED ins;
INSERT INTO [MAL-HQ-SQL01].[MallaghanApp].[dbo].[EmployeeClockIn] (Id,Employee,TASDateTimeStart,TMSDateTime,JobType)
VALUES ( NEWID(),#EmpID,0,#datetime, 'TMS')
Any help would be greatly appreciated as i dont know much about this stuff and i am really confused.

There are two issues with your trigger:
You need to use SET NOCOUNT ON to prevent the "rows done" messing up exepcted resultsets in some client drivers.
You need to take into account multiple (or zero) rows in the inserted table.
CREATE OR ALTER TRIGGER [dbo].[CopyTMSINFO]
ON [dbo].[d_iface_att]
AFTER INSERT
AS
SET NOCOUNT ON;
IF NOT EXISTS (SELECT 1 FROM inserted)
RETURN;
INSERT INTO [MAL-HQ-SQL01].MallaghanApp.dbo.EmployeeClockIn
(Id, Employee, TASDateTimeStart, TMSDateTime, JobType)
SELECT
NEWID(),
ins.emp_id,
0,
ins.date_and_time,
'TMS'
FROM inserted ins;
However, inserting into a linked server using a trigger is very bad form anyway. What happens if the remote server is offline?
You should instead use other replication methods, such as the remote server pulling data from this server using an Agent Job.

Related

With a DACPAC, how can I rename a column when there is a trigger on the table?

I'm trying to rename columns in a table for which there is a trigger. I've used SQL > Refactor > Rename to rename the column. And the trigger file also gets updated. However, when I publish, I get this:
Procedure TR_accrual_Accrual_Update, Line 134 Invalid column name
'MinHoursRule'.
That's the old column name. I'm assuming the publish is updating the table first, and sees that the current/old trigger still has the old column name.
Is it possible to rename a column, update the trigger, and publish?
The only solution I can really think of is to do this:
Delete the triggers and publish
Rename the columns
Add the triggers again
Publish
This is what I did as a work-around:
Add the new columns
Leave the old columns
Have the trigger use both sets of columns
Publish/deploy to prod soon
Remove the old columns
Publish/deploy to prod later
So, instead of renaming, I just created new columns, and then eventually deleted the old ones.
Yuck. But it worked.
Note: In our C# domain models, I only reference the new columns.
I guess that you have something wrong with the publish profile settings. You might have something disabled, for example "Do not modify triggers" or something like that. I just created new SSDT project in VS 2019 with following structure:
CREATE TABLE [dbo].[test]
(
[Id] INT ,
b int
)
GO
CREATE TRIGGER [dbo].[Trigger_test]
ON [dbo].[test]
FOR DELETE, INSERT, UPDATE
AS
BEGIN
SET NoCount ON
insert into test2 select b from inserted
END
GO
CREATE TABLE [dbo].[test2]
(
a int
)
GO
Published the project with default settings to the new database and made single insert to the dbo.test table. Made sure that there is record in dbo.test2 table. After that I re-factored dbo.test.b column to dbo.test.a then published again and everything worked. This is generated script:
/*
Deployment script for trg_test
This code was generated by a tool.
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
*/
GO
SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON;
SET NUMERIC_ROUNDABORT OFF;
GO
:setvar DatabaseName "trg_test"
:setvar DefaultFilePrefix "trg_test"
:setvar DefaultDataPath ""
:setvar DefaultLogPath ""
GO
:on error exit
GO
/*
Detect SQLCMD mode and disable script execution if SQLCMD mode is not supported.
To re-enable the script after enabling SQLCMD mode, execute the following:
SET NOEXEC OFF;
*/
:setvar __IsSqlCmdEnabled "True"
GO
IF N'$(__IsSqlCmdEnabled)' NOT LIKE N'True'
BEGIN
PRINT N'SQLCMD mode must be enabled to successfully execute this script.';
SET NOEXEC ON;
END
GO
USE [$(DatabaseName)];
GO
PRINT N'The following operation was generated from a refactoring log file 80d0e5de-e188-465e-b83c-18f38a1cec98';
PRINT N'Rename [dbo].[test].[b] to a';
GO
EXECUTE sp_rename #objname = N'[dbo].[test].[b]', #newname = N'a', #objtype = N'COLUMN';
GO
PRINT N'Altering Trigger [dbo].[Trigger_test]...';
GO
ALTER TRIGGER [dbo].[Trigger_test]
ON [dbo].[test]
FOR DELETE, INSERT, UPDATE
AS
BEGIN
SET NoCount ON
insert into test2 select a from inserted
END
GO
-- Refactoring step to update target server with deployed transaction logs
IF OBJECT_ID(N'dbo.__RefactorLog') IS NULL
BEGIN
CREATE TABLE [dbo].[__RefactorLog] (OperationKey UNIQUEIDENTIFIER NOT NULL PRIMARY KEY)
EXEC sp_addextendedproperty N'microsoft_database_tools_support', N'refactoring log', N'schema', N'dbo', N'table', N'__RefactorLog'
END
GO
IF NOT EXISTS (SELECT OperationKey FROM [dbo].[__RefactorLog] WHERE OperationKey = '80d0e5de-e188-465e-b83c-18f38a1cec98')
INSERT INTO [dbo].[__RefactorLog] (OperationKey) values ('80d0e5de-e188-465e-b83c-18f38a1cec98')
GO
GO
PRINT N'Update complete.';
GO

Inserting/Updating a SQL Server table using stored procedure in BizTalk

I am currently working on getting a set of records from a view in the Oracle database and trying to insert/update them in to the table in the SQL Server table depending on a column using BizTalk.
For this I created a stored procedure:
Create PROCEDURE [dbo].[uspInsertorUpdateDepartment]
#dept_name varchar(64),
#jax_dept_id char(32)
AS
BEGIN
SET NOCOUNT ON;
IF (SELECT TOP (1) 1 FROM afm.[jax_dept]
WHERE jax_dept_id = #jax_dept_id) IS NULL
INSERT INTO afm.[jax_dept](dept_name, jax_dept_id)
VALUES (#dept_name,#jax_dept_id)
ELSE
UPDATE afm.[jax_dept]
SET dept_name = #dept_name
WHERE jax_dept_id = #jax_dept_id
END
I created the schema for the stored procedure using consume adapter service. Used them in the mapping and the orchestration. Though I was not able to use the lopping functoid in the mapping
So removed the lopping and deployed the application. And tried to run and it ran without any error but just insert the first record from the oracle view in to the SQL Server database leaving all the other records. How can this be approached so the entire set of records from the oracle is inserted/updated in to SQL Server database.
Here I converted the separate update and insert into one merge statement:
Create PROCEDURE [dbo].[uspInsertorUpdateDepartment]
#dept_name varchar(64),
#jax_dept_id char(32)
AS
BEGIN
SET NOCOUNT ON;
merge afm.[jax_dept] as target
using (select #dept_name as dept_name, #jax_dept_id as jax_dept_id) as source
on source.jax_dept_id = target.jax_dept_id
when matched then
update target
SET dept_name = #dept_name
when not matched then
insert (dept_name, jax_dept_id)
values (#dept_name,#jax_dept_id)
;
END
Use table type as a parameter for the SP, instead of passing individually. We can
use looping functoid if we use User Defined Table value as a parameter.
CREATE TYPE dbo.SampleType AS TABLE
(
dept_name varchar(64) not null,
jax_dept_id char(32) not null
)
---
Create PROCEDURE [dbo].[uspInsertorUpdateDepartment]
#TVP dbo.SampleType READONLY
AS
BEGIN
SET NOCOUNT ON;
--your insert or update query
For more infor on how to use table value parameter check out this link:-
https://learn.microsoft.com/en-us/sql/relational-databases/tables/use-table-valued-parameters-database-engine

SQL Server events on insert

I have two tables in SQL Server. I want to raise an event when client inserts any row in order to copy that row to another table with more columns.
I have to do that in SQL Server just after insert. Is this possible? And if it is... how?
I need something like this:
CREATE EVENT myevent
ON (INSERT ROW?)
DO
TODO...
But I don't know if there are any event on insert and I donĀ“t know where does the code go.
Thanks.
EDIT:
I have another problem added. The tables are in different databases. I'm trying to implement this trigger:
USE [DB1]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [TRIGGER_NAME]
ON [dbo].[TABLE_TRIGGERED]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO DB2.[dbo].[FINAL_TABLE]
SELECT *
FROM INSERTED
WHERE COL1= 'Stuff' AND COL2= 'Stuff' AND COL3=
(
SELECT MAX(COL3)+1
FROM DB2[dbo].[FINAL_TABLE]
)
END
And it can't access to COL1, COL2 and COL3. Is my sintax right?
Using an SQL After Insert trigger, you can handle it
If this is your first time with triggers, take care of set based coding.
If you miss it, on INSERT statements with multiple rows you might get unexpected results. So keep away using variables in the trigger code, think always set based using the Inserted and Deleted tables special to triggers
You can check the referred tutorial

Trigger fire on each inserted row to insert into remote Table

I have two different SQL 2008 servers, I don't have permission to create a linked server in any of them.
i created a trigger on server1.table1 to insert the same record to the remote server server2.table1 using OPENROWSET
i created a stored procedure to insert this record, and i have no issue when i execute the stored procedure. it insert the recored into the remote server.
the problem is when i call the stored procedure from trigger, i get an error message.
can anyone help me please to solve this issue
Stored Procedure:
USE [DB1]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
alter PROCEDURE [dbo].[InsertIntoRemoteTable]
#Description nvarchar(50)
AS
insert into
OPENROWSET(
'SQLNCLI', 'Server=Server2;UID=MySRV2user;PWD=MySRV2Password',
'SELECT Description FROM [RemoteDB].[dbo].[Table_1]')
SELECT #Description
Trigger:
ALTER TRIGGER [dbo].[InsertTable1]
ON [DB1].[dbo].[Table_1]
for insert
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Desc nvarchar(50)
Select #Desc = i.Descr from INSERTED i;
EXEC InsertIntoRemoteTable #Desc
END
When i try to insert a new description value in the table i got the following error message:
"No row was updated
the data in row 1 was not committed
Error source .Net SqlClient Data provider.
Error Message: the operation could not be performed because OLE DB
provider "SQLNCLI10" for linked server "(null)" returned message "The partner transaction manager has disabled its support for remote/network transaction.".
correct the errors entry or press ESC to cancel the change(s).
can anyone help please on this
thanks
I think you have over complicated this. There is really no need for a stored procedure here to do this. You can do this insert into another database directly in your trigger with a simple insert statement. This removes a ton of complexity and it is set based.
ALTER TRIGGER [dbo].[InsertTable1]
ON [DB1].[dbo].[Table_1]
for insert
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO RemoteDB].[dbo].[Table_1](Description)
Select i.Descr
from INSERTED i;
END

SQL Server: pause a trigger

I am working with SQL Server 2005 and I have trigger on a table that will copy an deletions into another table. I cannot remove this trigger completely. My problem is that we have now developed an archiving strategy for this table. I need a way of "pausing" a trigger when the stored proc that does the archiving runs.
A little more detail would be useful on how the procedure is accessing the data, but assuming you are just getting the data, then deleting it from the table and wish to disable the trigger for this process, you can do the following
DISABLE TRIGGER trg ON tbl;
then
ENABLE TRIGGER trg ON tbl;
for the duration of the procedure.
This only works for SQL 2005+
An alternative method is to use Context_Info to disable it for a single session, while allowing other sessions to continue to fire the trigger.
Context_Info is a variable which belongs to the session. Its value can be changed using SET Context_Info.
The trigger will mostly look like this:
USE AdventureWorks;
GO
-- creating the table in AdventureWorks database
IF OBJECT_ID('dbo.Table1') IS NOT NULL
DROP TABLE dbo.Table1
GO
CREATE TABLE dbo.Table1(ID INT)
GO
-- Creating a trigger
CREATE TRIGGER TR_Test ON dbo.Table1 FOR INSERT,UPDATE,DELETE
AS
DECLARE #Cinfo VARBINARY(128)
SELECT #Cinfo = Context_Info()
IF #Cinfo = 0x55555
RETURN
PRINT 'Trigger Executed'
-- Actual code goes here
-- For simplicity, I did not include any code
GO
If you want to prevent the trigger from being executed you can do the following:
SET Context_Info 0x55555
INSERT dbo.Table1 VALUES(100)
Before issuing the INSERT statement, the context info is set to a value. In the trigger, we are first checking if the value of context info is the same as the value declared. If yes, the trigger will simply return without executing its code, otherwise the trigger will fire.
source: http://www.mssqltips.com/tip.asp?tip=1591
if DISABLE TRIGGER/ENABLE TRIGGER is not an option for some reason, you can create a table with a single row which will serve as a flag for the trigger.

Resources