After Trigger for Update and Insert failing - sql-server

I am writing a trigger for keeping audit record for one table for Insert and Update records.
CREATE TABLE [dbo].[AppLog](
[TableName] [varchar](32) NOT NULL,
[ColumnName] [varchar](32) NOT NULL,
[RecordId] [varchar](20) NOT NULL,
[OldValue] [varchar](2000) NULL,
[NewValue] [varchar](2000) NULL,
[UpdatedBy] [varchar](200) NULL,
[UpdatedOn] [datetime] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Persons](
[Personid] [int] IDENTITY(1,1) NOT NULL,
[LastName] [varchar](255) NOT NULL,
[FirstName] [varchar](255) NULL,
[Age] [int] NULL
) ON [PRIMARY]
GO
CREATE TRIGGER AuditRecord ON dbo.Persons
AFTER UPDATE, INSERT
AS
INSERT INTO AppLog
(TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,UpdatedBy ,UpdatedOn )
SELECT 'Persons', 'LastName', COALESCE(i.Personid,NULL),
d.LastName, i.LastName, CURRENT_USER, GETDATE()
FROM Persons pv
LEFT JOIN INSERTED i ON pv.Personid = i.Personid
LEFT JOIN DELETED d ON pv.Personid = d.Personid;
GO
INSERT INTO Persons (FirstName,LastName,age)
VALUES ('Satish','Parida',40);
INSERT INTO Persons (FirstName,LastName,age)
VALUES ('SKP','Tada',90);
The last insert is failing as it is trying to insert null to recordid column in applog table, could someone explain or fix the issue.

The statement that is failing is the one below:
INSERT INTO Persons (FirstName,LastName,age)
VALUES ('SKP','Tada',90);
This is because in your Trigger you are using Persons are your "base" table and the performing a LEFT JOIN to both inserted and deleted. As result when you try to perform the above INSERT, values from the previous INSERT are used as well in the trigger's dataset. The person 'Parida' doesn't appear in the table inserted for your second INSERT, and so COALESCE(i.Personid,NULL) returns NULL; as I mentioned in my comment, there' no point using COALESCE to return NULL, as if an expression's value evaluates to NULL it will return NULL. As RecordID (which is what COALESCE(i.Personid,NULL) is being inserted into) can't have the value NULL the INSERT fails and the whole transaction is rolled back.
I suspect that what you want for your trigger is the below:
CREATE TRIGGER AuditRecord ON dbo.Persons
AFTER UPDATE, INSERT
AS BEGIN
INSERT INTO AppLog (TableName,
ColumnName,
RecordId,
OldValue,
NewValue,
UpdatedBy,
UpdatedOn)
SELECT 'Persons',
'LastName',
i.Personid,
d.LastName,
i.LastName,
CURRENT_USER,
GETDATE()
FROM inserted AS i
LEFT JOIN deleted AS d ON i.Personid = d.Personid;
END;
inserted will always have at least 1 row for an UPDATE or an INSERT. inserted would not for a DELETE, but your trigger won't fire on that DML event so using inserted as the "base" table seems the correct choice.

Following code should work
CREATE TABLE [dbo].[AppLog](
[TableName] [varchar](32) NOT NULL,
[ColumnName] [varchar](32) NOT NULL,
[RecordId] [varchar](20) NOT NULL,
[OldValue] [varchar](2000) NULL,
[NewValue] [varchar](2000) NULL,
[UpdatedBy] [varchar](200) NULL,
[UpdatedOn] [datetime] NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Persons](
[Personid] [int] IDENTITY(1,1) NOT NULL,
[LastName] [varchar](255) NOT NULL,
[FirstName] [varchar](255) NULL,
[Age] [int] NULL
) ON [PRIMARY]
GO
CREATE TRIGGER AuditRecord ON dbo.Persons
AFTER UPDATE, INSERT
AS
if exists(SELECT * from inserted) and exists (SELECT * from deleted)
BEGIN
INSERT INTO AppLog
(TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,UpdatedBy ,UpdatedOn )
SELECT 'Persons', 'LastName', COALESCE(i.Personid,NULL),
d.LastName, i.LastName, CURRENT_USER, GETDATE()
FROM Persons pv
INNER JOIN INSERTED i ON pv.Personid = i.Personid
INNER JOIN DELETED d ON pv.Personid = d.Personid;
END
If exists (Select * from inserted) and not exists(Select * from deleted)
begin
INSERT INTO AppLog
(TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,UpdatedBy ,UpdatedOn )
SELECT
'Persons', 'LastName',i.Personid,NULL,i.LastName,CURRENT_USER,GETDATE()
FROM
inserted AS i
END
GO
INSERT INTO Persons (FirstName,LastName,age)
VALUES ('Satish','Parida',40);
INSERT INTO Persons (FirstName,LastName,age)
VALUES ('SKP','Tada',90);
INSERT INTO Persons (FirstName,LastName,age)
VALUES ('abc','def',90);
INSERT INTO Persons (FirstName,LastName,age)
VALUES ('gg','hh',90);
UPDATE dbo.Persons SET LastName='Paridachanged' WHERE Personid=1
SELECT * FROM Persons
SELECT * FROM AppLog

USE KnockKnockDev;
GO
IF OBJECT_ID('dbo.AuditRecord', 'TR') IS NOT NULL
DROP TRIGGER dbo.AuditRecord;
GO
CREATE TRIGGER AuditRecord ON dbo.Persons
AFTER UPDATE, INSERT, DELETE
AS
DECLARE #Action as char(1)
DECLARE #Count as int
DECLARE #TableName as char(32)
DECLARE #ColumnName as char (32)
SET #TableName = 'Persons'
SET #ColumnName = 'LastName'
SET #Action = 'I' -- Set Action to 'I'nsert by default.
SELECT #Count = COUNT(*) FROM DELETED
IF #Count > 0
BEGIN
SELECT #Count = COUNT(*) FROM INSERTED
IF #Count > 0
SET #Action = 'U' -- Set Action to 'U'pdated.
ELSE
SET #Action = 'D' -- Set Action to 'D'eleted.
END
IF #Action = 'I'
BEGIN
INSERT INTO AppLog
(TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,Action ,UpdatedBy ,UpdatedOn )
SELECT #TableName, #ColumnName, Personid,
NULL, LastName, #Action, CURRENT_USER, GETDATE()
FROM INSERTED;
END
ELSE IF #Action = 'D'
BEGIN
INSERT INTO AppLog
(TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,Action ,UpdatedBy ,UpdatedOn )
SELECT #TableName, #ColumnName, Personid,
LastName, NULL, #Action, CURRENT_USER, GETDATE()
FROM DELETED;
END
ELSE
BEGIN
INSERT INTO AppLog
(TableName ,ColumnName ,RecordId ,OldValue ,NewValue ,Action ,UpdatedBy ,UpdatedOn )
SELECT #TableName, #ColumnName, i.Personid,
d.LastName, i.LastName, #Action, CURRENT_USER, GETDATE()
FROM Persons pv
INNER JOIN INSERTED i ON pv.Personid = i.Personid
INNER JOIN DELETED d ON pv.Personid = d.Personid;
END
GO

Related

SQL Update Parent Child relation on Trigger

I would like to link rows in a self joined table with a trigger.
After an insert in a root table, I would like to create 3 "levels" in the child table.
And each of the level being a hierarchical data (or self joined) such as:
LVL1
LVL2
LVL3
Database is SQLSERVER.
I know there is a ton of material about self-joined and hierarchical SQL data, but ... I don't know I've not found what I expected. I've spent too many hours trying solutions, and searching online.
A link to SQLFiddle.
Here is the basic schema for example:
CREATE TABLE [dbo].[Root] (
[RootID] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[Name] [varchar](50)
)
GO
CREATE TABLE [dbo].[Child] (
[ChildID] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
[RootID] [int],
[Name] [varchar](50),
[ParentID] [int]
)
GO
ALTER TABLE [dbo].[Child] WITH CHECK ADD CONSTRAINT [Child_RootID_FK] FOREIGN KEY([RootID])
REFERENCES [dbo].[Root] ([RootID]) ON DELETE SET NULL
GO
ALTER TABLE [dbo].[Child] WITH CHECK ADD CONSTRAINT [Child_ParentID_FK] FOREIGN KEY([ParentID])
REFERENCES [dbo].[Child] ([ChildID])
GO
CREATE TRIGGER [dbo].[Root_TR]
ON [dbo].[Root]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[Child] ([RootID], [Name])
SELECT
I.[RootID],
CONCAT_WS('_', (SELECT [Name] FROM [dbo].[Root] R WHERE R.[RootID] = I.RootID), LVL.n )
FROM INSERTED I
CROSS JOIN (VALUES (1), (2), (3)) AS LVL(n)
END
GO
INSERT INTO [dbo].[Root] ([Name]) VALUES (
'Foo'
)
SELECT * FROM [Root]
SELECT * FROM [Child]
I have the current result:
ChildID
RootID
Name
ParentID
1
1
Foo_1
NULL
2
1
Foo_2
NULL
3
1
Foo_3
NULL
The expected result would be:
ChildID
RootID
Name
ParentID
1
1
Foo_1
NULL
2
1
Foo_2
1
3
1
Foo_3
2
I'm not sure how to achieve this.
I've found a close answer (here) involving usage of SEQUENCE
A solution may be something like:
DROP TRIGGER [dbo].[Root_TR]
GO
CREATE SEQUENCE [dbo].[Sequence] START WITH 1 INCREMENT BY 1
GO
CREATE TRIGGER [dbo].[Root_TR]
ON [dbo].[Root]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
ALTER SEQUENCE [dbo].[Sequence] RESTART
DECLARE #map TABLE ([ID] [int], [Seq] [int])
INSERT INTO [dbo].[Child] ([RootID], [Name])
OUTPUT [inserted].ChildID, NEXT VALUE FOR [dbo].[Sequence] INTO #map
SELECT
I.[RootID],
CONCAT_WS('_', (SELECT [Name] FROM [dbo].[Root] R WHERE R.[RootID] = I.RootID), LVL.n )
FROM INSERTED I
CROSS JOIN (VALUES (1), (2), (3)) AS LVL(n)
UPDATE C
SET C.[ParentID] = CASE
WHEN M.Seq = 1
THEN NULL
ELSE
(SELECT [Id] FROM #map WHERE [Seq] = [Seq] - 1)
END
FROM [dbo].Child C
INNER JOIN #map M ON C.ChildID = M.ID
END
GO
Unfortunately usage of NEXT VALUE FOR is not allowed in a OUTPUT clause.
Error 11720 NEXT VALUE FOR function is not allowed in the TOP, OVER, OUTPUT, ON, WHERE, GROUP BY, HAVING, or ORDER BY clauses.
I cannot relie on [Name] column to perform the UPDATE SET [ParentID] = ... FROM ... JOIN ...
There is a lot of answers regarding SQL self joined table but I can't really find the answer and my knowledge regarding SQL is limited.
I've attempted something like this
CREATE TRIGGER [dbo].[Root_TR]
ON [dbo].[Root]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
ALTER SEQUENCE [dbo].[Sequence] RESTART
DECLARE #map TABLE ([ChildID] [int], [Seq] [int])
DECLARE #i int = NEXT VALUE FOR [Sequence]
INSERT INTO [dbo].[Child] ([RootID], [Name])
OUTPUT [inserted].ChildID, #i AS [Seq] INTO #map
SELECT
I.[RootID],
CONCAT_WS('_', (SELECT [Name] FROM [dbo].[Root] R WHERE R.[RootID] = I.RootID), LVL.n )
FROM INSERTED I
CROSS JOIN (VALUES (1), (2), (3)) AS LVL(n)
DECLARE #xml xml = (SELECT * FROM #map FOR XML AUTO)
PRINT CONVERT(nvarchar(max), #xml)
UPDATE C
SET C.[ParentID] = CASE
WHEN M.Seq = 1
THEN NULL
ELSE
(SELECT [ChildID] FROM #map WHERE [Seq] = [Seq] - 1)
END
FROM [dbo].Child C
INNER JOIN #map M ON C.ChildID = M.ChildID
END
GO
Once again unfortunately the temporary TABLE #map is not filled correctly.
The #i is called once and do not increment for each output row.
ChildID
Seq
10
1
11
1
12
1
Another try was to use a DEFAULT. But I've an error when creating the trigger: "Column name or number of supplied values does not match table definition.". Probably because the OUTPUT clause see more columns available in #map TABLE than the number of columns in the OUTPUT.
CREATE TRIGGER [dbo].[Root_TR]
ON [dbo].[Root]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
ALTER SEQUENCE [dbo].[Sequence] RESTART
DECLARE #map TABLE (
[Seq] [int] PRIMARY KEY NOT NULL DEFAULT (NEXT VALUE FOR [Sequence]),
[ChildID] [int]
)
INSERT INTO [dbo].[Child] ([RootID], [Name])
OUTPUT [inserted].ChildID INTO #map
SELECT
I.[RootID],
CONCAT_WS('_', (SELECT [Name] FROM [dbo].[Root] R WHERE R.[RootID] = I.RootID), LVL.n )
FROM INSERTED I
CROSS JOIN (VALUES (1), (2), (3)) AS LVL(n)
DECLARE #xml xml = (SELECT * FROM #map FOR XML AUTO)
PRINT CONVERT(nvarchar(max), #xml)
UPDATE C
SET C.[ParentID] = CASE
WHEN M.Seq = 1
THEN NULL
ELSE
(SELECT [ChildID] FROM #map WHERE [Seq] = [Seq] - 1)
END
FROM [dbo].Child C
INNER JOIN #map M ON C.ChildID = M.ChildID
END
GO
And the last try was to use a #table (I do not distinguish clearly between #x TABLE, TABLE #x, TABLE x). But I want to scope the temporary table to the trigger, and not make the table available globally.
So, this time the TRIGGER is created. But when fired, the error message is Invalid object name 'Sequence'. I don't know why the [Sequence] object is not available in this #table.
CREATE TRIGGER [dbo].[Root_TR]
ON [dbo].[Root]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
ALTER SEQUENCE [dbo].[Sequence] RESTART
CREATE TABLE #map (
[Seq] [int] PRIMARY KEY NOT NULL DEFAULT (NEXT VALUE FOR [Sequence]),
[ChildID] [int] NOT NULL
)
INSERT INTO [dbo].[Child] ([RootID], [Name])
OUTPUT [inserted].ChildID INTO #map
SELECT
I.[RootID],
CONCAT_WS('_', (SELECT [Name] FROM [dbo].[Root] R WHERE R.[RootID] = I.RootID), LVL.n )
FROM INSERTED I
CROSS JOIN (VALUES (1), (2), (3)) AS LVL(n)
DECLARE #xml xml = (SELECT * FROM #map FOR XML AUTO)
PRINT CONVERT(nvarchar(max), #xml)
UPDATE C
SET C.[ParentID] = CASE
WHEN M.Seq = 1
THEN NULL
ELSE
(SELECT [ChildID] FROM #map WHERE [Seq] = [Seq] - 1)
END
FROM [dbo].Child C
INNER JOIN #map M ON C.ChildID = M.ChildID
END
GO
So finally I don't have yet any solution to properly link my different levels with their parents.
Any help would be highly appreciated.
Here the complete trigger.
CREATE TRIGGER [dbo].[Root_TR]
ON [dbo].[Root]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #map (
[Seq] [int] PRIMARY KEY NOT NULL IDENTITY(1,1)
[ChildID] [int] NOT NULL
)
INSERT INTO [dbo].[Child] ([RootID], [Name])
OUTPUT INSERTED.ChildID INTO #map
SELECT
I.[RootID],
CONCAT_WS('_', (SELECT [Name] FROM [dbo].[Root] R WHERE R.[RootID] = I.RootID), LVL.n )
FROM INSERTED I
CROSS JOIN (VALUES (1), (2), (3)) AS LVL(n)
UPDATE C
SET C.[ParentID] = CASE
WHEN M.[Seq] = 1
THEN NULL
ELSE
(SELECT [ChildID] FROM #map WHERE [Seq] = M.[Seq] - 1)
END
FROM [dbo].Child C
INNER JOIN #map M ON C.ChildID = M.ChildID
END
GO

Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMITS

I have the following error when I run a stored procedure in SQL:
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
What does this mean? How could I solve it?
Thank you very much.
/****** Object: StoredProcedure [SingleDirectory].[SPTADIR_EntityIdentification] Script Date: 26/04/2021 9:37:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [SingleDirectory].[SPTADIR_EntityIdentification]
-- Add the parameters for the stored procedure here
#xmlEntity nvarchar(MAX) = NULL
AS
SET XACT_ABORT ON
BEGIN TRAN
BEGIN TRY
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE
#handle int,
#currentDateTime datetime
-- =============================================
--- Protection Against Concurrent Executions
-- =============================================
DECLARE #RC INT
DECLARE #message VARCHAR(500)
SELECT #message = CONVERT(VARCHAR(30), GETDATE(), 121) + ': Try to obtain a lock ..'
--RAISERROR(#message, 0, 1) WITH NOWAIT;
EXEC #RC = sp_getapplock
#Resource = '[SingleDirectory].[SPTADIR_EntityIdentification]',
#LockMode = 'Exclusive',
#LockOwner = 'Transaction',
#LockTimeout = 6000 -- 0.1 minute
IF #RC < 0
BEGIN
IF ##TRANCOUNT > 0 ROLLBACK TRAN;
SELECT #message = CONVERT(VARCHAR(30), GETDATE(), 121) + ': Sorry, could not obtain a lock within the timeout period, return code was ' + CONVERT(VARCHAR(30), #RC) + '.'
--RAISERROR(#message, 0, 1) WITH NOWAIT;
RETURN #RC
END
ELSE
BEGIN
SELECT #message = CONVERT(VARCHAR(30), GETDATE(), 121) + ': AppLock obtained ..'
--RAISERROR(#message, 0, 1) WITH NOWAIT;
END
-- ******************************
-- 1.- Creates tables
-- ******************************
-- TADIR_Entity identification
CREATE TABLE [#tmpEntity] (
[EntityId] [int] NULL,
[EntityType] [int] NOT NULL,
[VendorId] [int] NULL,
[ProviderEntityId] [varchar](100) COLLATE Latin1_General_100_CI_AS_SC NULL,
[FiscalId] [varchar](15) COLLATE Latin1_General_100_CI_AS_SC NULL,
[BusinessName] [nvarchar](150) COLLATE Latin1_General_100_CI_AS_SC NULL,
[AddressName] [varchar](100) COLLATE Latin1_General_100_CI_AS_SC NULL,
[PostalCode] [varchar](10) COLLATE Latin1_General_100_CI_AS_SC NULL,
[CityName] [varchar](50) COLLATE Latin1_General_100_CI_AS_SC NULL,
[CountryDescr] [varchar](50) COLLATE Latin1_General_100_CI_AS_SC NULL,
[StateId] [int] NULL,
[PhoneNbr] [varchar](20) COLLATE Latin1_General_100_CI_AS_SC NULL,
[SystemId] [int] NULL,
[ActiveFlag] [bit] NOT NULL,
[ISO2Value] [varchar](2) COLLATE Latin1_General_100_CI_AS_SC NULL,
[ISO3Value] [varchar](3) COLLATE Latin1_General_100_CI_AS_SC NULL,
[InfoBusinessTypeId] [int] NULL
)
CREATE CLUSTERED INDEX INDEXEntityId ON [#tmpEntity] (EntityId)
CREATE NONCLUSTERED INDEX INDEXProviderEntityId ON [#tmpEntity] (ISO2Value, ProviderEntityId, EntityId)
CREATE NONCLUSTERED INDEX INDEXFiscalId ON [#tmpEntity] (ISO2Value, FiscalId, EntityId)
-- New TADIR_Entity
CREATE TABLE [#tmpEntityInserted] (
[EntityId] [int] NULL,
[VendorId] [int] NULL,
[ProviderEntityId] [varchar](100) COLLATE Latin1_General_100_CI_AS_SC NULL
)
CREATE CLUSTERED INDEX INDEXProviderEntityId ON [#tmpEntityInserted] (VendorId, ProviderEntityId)
-- TADIR_EntityIDs
CREATE TABLE [#tmpEntityIDs] (
[EntityId] [int] NULL,
[VendorId] [int] NULL,
[ProviderEntityId] [varchar](100) COLLATE Latin1_General_100_CI_AS_SC NULL,
[IDType] [tinyint] NULL,
[IdentificationValue] [varchar](50) COLLATE Latin1_General_100_CI_AS_SC NULL
)
CREATE NONCLUSTERED INDEX INDEXProviderEntityId ON [#tmpEntityIDs] (VendorId, ProviderEntityId)
CREATE NONCLUSTERED INDEX INDEXEntityId ON [#tmpEntityIDs] (EntityId, IDType)
-- ******************************
-- 2.- Parses XML and inserts into [#tmpEntity] and [#tmpEntityIDs]
-- ******************************
-- XML
CREATE TABLE [#tmpEntityXml] (
[EntityId] [int] NULL,
[EntityType] [int] NOT NULL,
[VendorId] [int] NULL,
[ProviderEntityId] [varchar](100) COLLATE Latin1_General_100_CI_AS_SC NULL,
[FiscalId] [varchar](15) COLLATE Latin1_General_100_CI_AS_SC NULL,
[BusinessName] [nvarchar](150) COLLATE Latin1_General_100_CI_AS_SC NULL,
[AddressName] [varchar](100) COLLATE Latin1_General_100_CI_AS_SC NULL,
[PostalCode] [varchar](10) COLLATE Latin1_General_100_CI_AS_SC NULL,
[CityName] [varchar](50) COLLATE Latin1_General_100_CI_AS_SC NULL,
[CountryDescr] [varchar](50) COLLATE Latin1_General_100_CI_AS_SC NULL,
[StateId] [int] NULL,
[PhoneNbr] [varchar](20) COLLATE Latin1_General_100_CI_AS_SC NULL,
[SystemId] [int] NULL,
[ActiveFlag] [bit] NOT NULL,
[ISO2Value] [varchar](2) COLLATE Latin1_General_100_CI_AS_SC NULL,
[ISO3Value] [varchar](3) COLLATE Latin1_General_100_CI_AS_SC NULL,
[InfoBusinessTypeId] [int] NULL,
[IDType] [tinyint] NULL,
[IdentificationValue] [varchar](50) COLLATE Latin1_General_100_CI_AS_SC NULL
)
exec sp_xml_preparedocument #handle OUTPUT, #xmlEntity
INSERT INTO [#tmpEntityXml] (
[EntityId],
[EntityType],
[VendorId],
[ProviderEntityId],
[FiscalId],
[BusinessName],
[AddressName],
[PostalCode],
[CityName],
[CountryDescr],
[StateId],
[PhoneNbr],
[SystemId],
[ActiveFlag],
[ISO2Value],
[ISO3Value],
[InfoBusinessTypeId],
[IDType],
[IdentificationValue])
SELECT (CASE WHEN EntityId = 0 THEN NULL ELSE EntityId END) AS EntityId,
EntityType,
(CASE WHEN VendorId = 0 THEN NULL ELSE VendorId END) AS VendorId,
(CASE WHEN ProviderEntityId IS NULL THEN NULL ELSE ProviderEntityId END) AS ProviderEntityId,
FiscalId,
BusinessName,
AddressName,
PostalCode,
CityName,
CountryDescr,
(CASE WHEN StateId = 0 THEN NULL ELSE StateId END) AS StateId,
PhoneNbr,
(CASE WHEN SystemId = 0 THEN NULL ELSE SystemId END) AS SystemId,
ActiveFlag,
ISO2Value,
ISO3Value,
(CASE WHEN InfoBusinessTypeId = 0 THEN NULL ELSE InfoBusinessTypeId END) AS InfoBusinessTypeId,
(CASE WHEN IDType = 0 THEN NULL ELSE IDType END) AS IDType,
IdentificationValue
FROM OPENXML (#handle, 'ArrayOfIdentificationEntity/IdentificationEntity',3)
WITH (
EntityId int 'EntityId',
EntityType int 'EntityType',
VendorId int 'VendorId',
ProviderEntityId varchar(100) 'ProviderEntityId',
FiscalId varchar(15) 'FiscalId',
BusinessName nvarchar(150) 'BusinessName',
AddressName varchar(100) 'AddressName',
PostalCode varchar(10) 'PostalCode',
CityName varchar(50) 'CityName',
CountryDescr varchar(50) 'CountryDescr',
StateId int 'StateId',
PhoneNbr varchar(20) 'PhoneNbr',
SystemId int 'SystemId',
ActiveFlag bit 'ActiveFlag',
ISO2Value varchar(2) 'ISO2Value',
ISO3Value varchar(3) 'ISO3Value',
InfoBusinessTypeId int 'InfoBusinessTypeId',
IDType tinyint 'IDType',
IdentificationValue varchar(50) 'IdentificationValue') AS fbEntity
EXEC sp_xml_removedocument #handle
UPDATE [#tmpEntityXml]
SET EntityId = [SingleDirectory].[TADIR_Entity].EntityId
FROM [SingleDirectory].[TADIR_Entity]
INNER JOIN [#tmpEntityXml]
ON ([SingleDirectory].[TADIR_Entity].[VendorId] = [#tmpEntityXml].[VendorId]
AND [SingleDirectory].[TADIR_Entity].[ProviderEntityId] = [#tmpEntityXml].[ProviderEntityId] AND [SingleDirectory].[TADIR_Entity].EntityType = [#tmpEntityXml].EntityType)
UPDATE [#tmpEntityXml]
SET EntityId = [SingleDirectory].[TADIR_Entity].EntityId
FROM [SingleDirectory].[TADIR_Entity]
INNER JOIN [#tmpEntityXml]
ON ([SingleDirectory].[TADIR_Entity].[VendorId] = [#tmpEntityXml].[VendorId]
AND [SingleDirectory].[TADIR_Entity].FiscalId = [#tmpEntityXml].FiscalId AND [SingleDirectory].[TADIR_Entity].EntityType = [#tmpEntityXml].EntityType)
-- Inserts tmpEntity
INSERT INTO [#tmpEntity]
([EntityId], [EntityType], [VendorId], [ProviderEntityId],
[FiscalId], [BusinessName], [AddressName], [PostalCode],
[CityName], [CountryDescr], [StateId], [PhoneNbr],
[SystemId], [ActiveFlag], [ISO2Value], [ISO3Value],
[InfoBusinessTypeId])
SELECT DISTINCT [EntityId], [EntityType], [VendorId], [ProviderEntityId],
[FiscalId], [BusinessName], [AddressName], [PostalCode],
[CityName], [CountryDescr], [StateId], [PhoneNbr], [SystemId],
[ActiveFlag], [ISO2Value], [ISO3Value], [InfoBusinessTypeId]
FROM [#tmpEntityXml]
WHERE VendorId IS NOT NULL AND ProviderEntityId IS NOT NULL AND ISO2Value IS NOT NULL
-- Inserts tmpEntityIDs
INSERT INTO [#tmpEntityIDs]
([EntityId], [VendorId], [ProviderEntityId], [IDType], [IdentificationValue])
SELECT DISTINCT [EntityId], [VendorId], [ProviderEntityId], [IDType], [IdentificationValue]
FROM [#tmpEntityXml]
WHERE VendorId IS NOT NULL AND ProviderEntityId IS NOT NULL AND ISO2Value IS NOT NULL AND
IDType IS NOT NULL AND IdentificationValue IS NOT NULL
-- Drops table
DROP TABLE [#tmpEntityXml];
-- ******************************
-- 3.- TADIR_Entity
-- ******************************
-- 3.1.- Update TADIR_Entity (when necessary)
UPDATE [SingleDirectory].[TADIR_Entity]
SET [ActiveFlag] = [#tmpEntity].[ActiveFlag],
[AddressName] = (CASE WHEN [#tmpEntity].[AddressName] IS NOT NULL THEN [#tmpEntity].[AddressName] ELSE [SingleDirectory].[TADIR_Entity].[AddressName] END),
[BusinessName] = (CASE WHEN [#tmpEntity].[BusinessName] IS NOT NULL THEN [#tmpEntity].[BusinessName] ELSE [SingleDirectory].[TADIR_Entity].[BusinessName] END),
[CityName] = (CASE WHEN [#tmpEntity].[CityName] IS NOT NULL THEN [#tmpEntity].[CityName] ELSE [SingleDirectory].[TADIR_Entity].[CityName] END),
[CountryDescr] = (CASE WHEN [#tmpEntity].[CountryDescr] IS NOT NULL THEN [#tmpEntity].[CountryDescr] ELSE [SingleDirectory].[TADIR_Entity].[CountryDescr] END),
[EntityType] = [#tmpEntity].[EntityType],
[FiscalId] = (CASE WHEN [#tmpEntity].[FiscalId] IS NOT NULL THEN [#tmpEntity].[FiscalId] ELSE [SingleDirectory].[TADIR_Entity].[FiscalId] END),
[ISO2Value] = (CASE WHEN [#tmpEntity].[ISO2Value] IS NOT NULL THEN [#tmpEntity].[ISO2Value] ELSE [SingleDirectory].[TADIR_Entity].[ISO2Value] END),
[ISO3Value] = (CASE WHEN [#tmpEntity].[ISO3Value] IS NOT NULL THEN [#tmpEntity].[ISO3Value] ELSE [SingleDirectory].[TADIR_Entity].[ISO3Value] END),
[InfoBusinessTypeId] = (CASE WHEN [#tmpEntity].[InfoBusinessTypeId] IS NOT NULL THEN [#tmpEntity].[InfoBusinessTypeId] ELSE [SingleDirectory].[TADIR_Entity].[InfoBusinessTypeId] END),
[PhoneNbr] = (CASE WHEN [#tmpEntity].[PhoneNbr] IS NOT NULL THEN [#tmpEntity].[PhoneNbr] ELSE [SingleDirectory].[TADIR_Entity].[PhoneNbr] END),
[PostalCode] = (CASE WHEN [#tmpEntity].[PostalCode] IS NOT NULL THEN [#tmpEntity].[PostalCode] ELSE [SingleDirectory].[TADIR_Entity].[PostalCode] END),
[ProviderEntityId] = (CASE WHEN [#tmpEntity].[ProviderEntityId] IS NOT NULL THEN [#tmpEntity].[ProviderEntityId] ELSE [SingleDirectory].[TADIR_Entity].[ProviderEntityId] END),
[StateId] = (CASE WHEN [#tmpEntity].[StateId] NOT LIKE 0 THEN [#tmpEntity].[StateId] ELSE [SingleDirectory].[TADIR_Entity].[StateId] END),
[SystemId] = (CASE WHEN [SingleDirectory].[TADIR_Entity].[SystemId] IS NULL THEN [#tmpEntity].[SystemId] ELSE [SingleDirectory].[TADIR_Entity].[SystemId] END),
[VendorId] = [#tmpEntity].[VendorId],
[UpdateDate] = GETUTCDATE()
FROM [SingleDirectory].[TADIR_Entity]
INNER JOIN [#tmpEntity]
ON ([SingleDirectory].[TADIR_Entity].[EntityId] = [#tmpEntity].[EntityId])
WHERE ([SingleDirectory].[TADIR_Entity].[ActiveFlag] IS NULL AND [#tmpEntity].[ActiveFlag] IS NOT NULL) OR ([SingleDirectory].[TADIR_Entity].[ActiveFlag] IS NOT NULL AND [#tmpEntity].[ActiveFlag] IS NULL) OR [SingleDirectory].[TADIR_Entity].[ActiveFlag]
NOT LIKE [#tmpEntity].[ActiveFlag]
OR ( [#tmpEntity].[AddressName] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[AddressName] IS NULL OR [SingleDirectory].[TADIR_Entity].[AddressName] NOT LIKE [#tmpEntity].[AddressName]))
OR ( [#tmpEntity].[BusinessName] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[BusinessName] IS NULL OR [SingleDirectory].[TADIR_Entity].[BusinessName] NOT LIKE [#tmpEntity].[BusinessName]))
OR ( [#tmpEntity].[CityName] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[CityName] IS NULL OR [SingleDirectory].[TADIR_Entity].[CityName] NOT LIKE [#tmpEntity].[CityName]))
OR ( [#tmpEntity].[CountryDescr] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[CountryDescr] IS NULL OR [SingleDirectory].[TADIR_Entity].[CountryDescr] NOT LIKE [#tmpEntity].[CountryDescr]))
OR ( [SingleDirectory].[TADIR_Entity].[EntityType] IS NULL AND [#tmpEntity].[EntityType] IS NOT NULL) OR ([SingleDirectory].[TADIR_Entity].[EntityType] IS NOT NULL AND [#tmpEntity].[EntityType] IS NULL) OR [SingleDirectory].[TADIR_Entity].[EntityType] NOT LIKE [#tmpEntity].[EntityType]
OR ( [#tmpEntity].[FiscalId] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[FiscalId] IS NULL OR [SingleDirectory].[TADIR_Entity].[FiscalId] NOT LIKE [#tmpEntity].[FiscalId]))
OR ( [#tmpEntity].[ISO2Value] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[ISO2Value] IS NULL OR [SingleDirectory].[TADIR_Entity].[ISO2Value] NOT LIKE [#tmpEntity].[ISO2Value]))
OR ( [#tmpEntity].[ISO3Value] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[ISO3Value] IS NULL OR [SingleDirectory].[TADIR_Entity].[ISO3Value] NOT LIKE [#tmpEntity].[ISO3Value]))
OR ( [#tmpEntity].[InfoBusinessTypeId] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[InfoBusinessTypeId] IS NULL OR [SingleDirectory].[TADIR_Entity].[InfoBusinessTypeId] NOT LIKE [#tmpEntity].[InfoBusinessTypeId]))
OR ( [#tmpEntity].[PhoneNbr] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[PhoneNbr] IS NULL OR [SingleDirectory].[TADIR_Entity].[PhoneNbr] NOT LIKE [#tmpEntity].[PhoneNbr]))
OR ( [#tmpEntity].[PostalCode] IS NOT NULL AND ([SingleDirectory].[TADIR_Entity].[PostalCode] IS NULL OR [SingleDirectory].[TADIR_Entity].[PostalCode] NOT LIKE [#tmpEntity].[PostalCode]))
OR ( [SingleDirectory].[TADIR_Entity].[ProviderEntityId] IS NULL AND [#tmpEntity].[ProviderEntityId] IS NOT NULL) OR ([SingleDirectory].[TADIR_Entity].[ProviderEntityId] IS NOT NULL AND [#tmpEntity].[ProviderEntityId] IS NULL) OR [SingleDirectory].[TADIR_Entity].[ProviderEntityId] NOT LIKE [#tmpEntity].[ProviderEntityId]
OR ( [#tmpEntity].[StateId] NOT LIKE 0 AND ([SingleDirectory].[TADIR_Entity].[StateId] IS NULL OR [SingleDirectory].[TADIR_Entity].[StateId] NOT LIKE [#tmpEntity].[StateId]))
OR ([SingleDirectory].[TADIR_Entity].[SystemId] IS NULL)
OR ( [SingleDirectory].[TADIR_Entity].[VendorId] IS NULL AND [#tmpEntity].[VendorId] IS NOT NULL) OR ( [SingleDirectory].[TADIR_Entity].[VendorId] IS NOT NULL AND [#tmpEntity].[VendorId] IS NULL) OR [SingleDirectory].[TADIR_Entity].[VendorId] NOT LIKE [#tmpEntity].[VendorId]
-- 3.2.- INSERTS into TADIR_Entity not identified emtotoes
SET #currentDateTime = GETUTCDATE()
-- INSERT INTO TADIR_Entity
INSERT INTO [SingleDirectory].[TADIR_Entity] ([EntityType],
[VendorId],
[ProviderEntityId],
[FiscalId],
[BusinessName],
[AddressName],
[PostalCode],
[CityName],
[CountryDescr],
[StateId],
[PhoneNbr],
[SystemId],
[ActiveFlag],
[ISO2Value],
[ISO3Value],
[InfoBusinessTypeId],
[CreationDate],
[UpdateDate])
OUTPUT INSERTED.EntityId, INSERTED.VendorId, INSERTED.ProviderEntityId INTO [#tmpEntityInserted]
SELECT [#tmpEntity].[EntityType],
[#tmpEntity].[VendorId],
[#tmpEntity].[ProviderEntityId],
[#tmpEntity].[FiscalId],
[#tmpEntity].[BusinessName],
[#tmpEntity].[AddressName],
[#tmpEntity].[PostalCode],
[#tmpEntity].[CityName],
[#tmpEntity].[CountryDescr],
[#tmpEntity].[StateId],
[#tmpEntity].[PhoneNbr],
[#tmpEntity].[SystemId],
[#tmpEntity].[ActiveFlag],
[#tmpEntity].[ISO2Value],
[#tmpEntity].[ISO3Value],
[#tmpEntity].[InfoBusinessTypeId],
#currentDateTime,
#currentDateTime
FROM [#tmpEntity]
WHERE [#tmpEntity].[EntityId] IS NULL
-- UPDATE [#tmpEntityXml].[EntityId]
UPDATE [#tmpEntity]
SET [EntityId] = [#tmpEntityInserted].[EntityId]
FROM [#tmpEntity]
INNER JOIN [#tmpEntityInserted]
ON ([#tmpEntity].[ProviderEntityId] = [#tmpEntityInserted].[ProviderEntityId]
AND [#tmpEntity].[VendorId] = [#tmpEntityInserted].[VendorId])
-- 3.3.- Update EntityId ON [#tmpEntityIDs]
UPDATE [#tmpEntityIDs]
SET [EntityId] = [#tmpEntity].[EntityId]
FROM [#tmpEntityIDs]
INNER JOIN [#tmpEntity]
ON ([#tmpEntityIDs].[VendorId] = [#tmpEntity].[VendorId]
AND [#tmpEntityIDs].[ProviderEntityId] = [#tmpEntity].[ProviderEntityId]
AND [#tmpEntityIDs].[EntityId] IS NULL)
-- ******************************
-- 4.- TADIR_EntityIDs
-- ******************************
-- 4.1.- DELETE old values
DELETE [SingleDirectory].[TADIR_EntityIDs]
FROM [SingleDirectory].[TADIR_EntityIDs]
INNER JOIN [#tmpEntity]
ON ([SingleDirectory].[TADIR_EntityIDs].[EntityId] = [#tmpEntity].[EntityId])
LEFT JOIN [#tmpEntityIDs]
ON ([SingleDirectory].[TADIR_EntityIDs].[EntityId] = [#tmpEntityIDs].[EntityId]
AND [SingleDirectory].[TADIR_EntityIDs].[IDType] = [#tmpEntityIDs].[IDType])
WHERE [#tmpEntityIDs].[EntityId] IS NULL
-- 4.2.- UPDATE values
UPDATE [SingleDirectory].[TADIR_EntityIDs]
SET [IdentificationValue] = [#tmpEntityIDs].[IdentificationValue]
FROM [SingleDirectory].[TADIR_EntityIDs]
INNER JOIN [#tmpEntityIDs]
ON ([#tmpEntityIDs].[EntityId] = [SingleDirectory].[TADIR_EntityIDs].[EntityId] AND
[#tmpEntityIDs].[IDType] = [SingleDirectory].[TADIR_EntityIDs].[IDType])
WHERE [#tmpEntityIDs].[IdentificationValue] NOT LIKE [SingleDirectory].[TADIR_EntityIDs].[IdentificationValue]
-- 4.3.- INSERT values
INSERT INTO [SingleDirectory].[TADIR_EntityIDs] ([EntityId],
[IDType],
[IdentificationValue])
SELECT [#tmpEntityIDs].[EntityId],
[#tmpEntityIDs].[IDType],
[#tmpEntityIDs].[IdentificationValue]
FROM [#tmpEntityIDs]
LEFT JOIN [SingleDirectory].[TADIR_EntityIDs]
ON ([#tmpEntityIDs].[EntityId] = [SingleDirectory].[TADIR_EntityIDs].[EntityId]
AND [#tmpEntityIDs].[IDType] = [SingleDirectory].[TADIR_EntityIDs].[IDType])
WHERE [SingleDirectory].[TADIR_EntityIDs].[EntityId] IS NULL
-- ******************************
-- 5.- Loads the return results.
-- ******************************
SELECT DISTINCT [SingleDirectory].[TADIR_Entity].*, [SingleDirectory].[TADIR_EntityIDs].[IDType], [SingleDirectory].[TADIR_EntityIDs].[IdentificationValue]
FROM [SingleDirectory].[TADIR_Entity]
INNER JOIN [#tmpEntity]
ON ([SingleDirectory].[TADIR_Entity].[EntityId] = [#tmpEntity].[EntityId] )
LEFT JOIN [SingleDirectory].[TADIR_EntityIDs]
ON ([SingleDirectory].[TADIR_Entity].[EntityId] = [SingleDirectory].[TADIR_EntityIDs].[EntityId])
WHERE [#tmpEntity].[EntityId] IS NOT NULL
-- ******************************
-- 6.- Free memory
-- ******************************
DROP INDEX INDEXEntityId ON [#tmpEntity]
DROP INDEX INDEXProviderEntityId ON [#tmpEntity]
DROP INDEX INDEXFiscalId ON [#tmpEntity]
DROP TABLE [#tmpEntity]
DROP INDEX INDEXProviderEntityId ON [#tmpEntityInserted]
DROP TABLE [#tmpEntityInserted]
DROP INDEX INDEXProviderEntityId ON [#tmpEntityIDs]
DROP INDEX INDEXEntityId ON [#tmpEntityIDs]
DROP TABLE [#tmpEntityIDs]
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN;
INSERT INTO [Log].[tasip_errorlogdb]
(errorcode,
errorstatusvalue,
procedurevalue,
descriptionmessagetext,
wrongtracecode,
date)
VALUES (Error_number(),
Error_state(),
Error_procedure(),
Error_message(),
Error_line(),
Getutcdate());
SELECT ERROR_MESSAGE() AS ErrorMessage;
END CATCH
IF ##TRANCOUNT > 0
COMMIT TRAN;

MSSQL Trigger Update on column

I have 2 tables and I want table 1 to have a trigger that insert or update in table 2, but I'm not sure how to do that.
Table 1:
CREATE TABLE [dbo].[DevicePorts](
[ID] [int] IDENTITY(1,1) NOT NULL,
[IsInUse] [bit] NOT NULL,
)
Table 2:
CREATE TABLE [dbo].[DevicePortActivities](
[ID] [uniqueidentifier] NOT NULL,
[StartTime] [datetimeoffset](7) NOT NULL,
[EndTime] [datetimeoffset](7) NULL,
[FK_DevicePortID] [int] NOT NULL FOREIGN KEY REFERENCES DevicePorts(ID),
)
Start of my trigger:
CREATE TRIGGER PortInUse
ON DevicePorts
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
IF UPDATE (IsInUse)
BEGIN
IF IsInUse = 1
THEN
INSERT INTO [dbo].[DevicePortActivities]
(
[ID]
,[StartTime]
,[EndTime]
,[FK_DevicePortID]
)
VALUES
(
NEWID(),
SYSDATETIMEOFFSET(),
null,
<DevicePortID>
)
ELSE
UPDATE [dbo].[DevicePortActivities]
SET EndTime = SYSDATETIMEOFFSET()
WHERE FK_DevicePortID = <DevicePortID> AND EndTime is null
END
END
END
GO
What I'm trying to do is when 'IsInUse' is modified it should insert a row into 'DevicePortActivities' or update.
Conditions are, if 'IsInUse' is true then it should insert a record, if it's false it should update the last record where 'EndTime' is null.
You need to treat inserted as a table. I'd suggest looking at MERGE for this (because different rows may have had different changes applied by a single UPDATE).
Something like:
CREATE TRIGGER PortInUse
ON DevicePorts
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
MERGE INTO [dbo].[DevicePortActivities] t
USING (select i.ID,i.IsInUse as NewUse,d.IsInUse as OldUse
from inserted i inner join deleted d on i.ID = d.ID) s
ON
t.FK_DevicePortID = s.ID
WHEN MATCHED AND t.EndTime is null AND NewUse = 0 and OldUse = 1
THEN UPDATE SET EndTime = SYSDATETIMEOFFSET()
WHEN NOT MATCHED AND NewUse = 1 and OldUse = 0
THEN INSERT ([ID]
,[StartTime]
,[EndTime]
,[FK_DevicePortID])
VALUES (NEWID(),
SYSDATETIMEOFFSET(),
null,
s.ID);
END
I found a solution for my question
CREATE TRIGGER [dbo].[PortInUse]
ON [dbo].[DevicePorts]
AFTER UPDATE
AS BEGIN
SET NOCOUNT ON;
IF UPDATE (IsInUse)
BEGIN
DECLARE #IsInUse bit;
DECLARE #PortID int;
SELECT #IsInUse = i.IsInUse FROM inserted i;
SELECT #PortID = i.ID FROM inserted i;
IF (#IsInUse = 1)
INSERT INTO [dbo].[DevicePortActivities]
(
[ID]
,[StartTime]
,[EndTime]
,[FK_DevicePortID]
)
VALUES
(
NEWID(),
SYSDATETIMEOFFSET(),
null,
#PortID
);
ELSE
UPDATE [dbo].[DevicePortActivities]
SET EndTime = SYSDATETIMEOFFSET()
WHERE FK_DevicePortID = #PortID AND EndTime is null;
END
END
I'm not sure if there is a better way to do this, but it's working.

Statement contains an OUTPUT clause without INTO clause error using trigger in SQL Server 2012?

I have a trigger for auditing record insert,update and delete. My code is
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[mytable_insertafter_audit]
ON [dbo].[mytable]
AFTER INSERT, DELETE, UPDATE
AS
BEGIN
SET NOCOUNT ON;
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.
WHEN EXISTS(SELECT * FROM DELETED)
THEN 'D' -- Set Action to Deleted.
ELSE NULL -- Skip. It may have been a "failed delete".
END)
IF (#Action = 'I')
BEGIN
INSERT INTO audit_trg
SELECT
lr.sanction_status, i.sanction_status,
GETDATE(), lr.id, 'mytable', #Action
FROM
mytable lr
INNER JOIN
INSERTED i ON i.id = lr.id
END
ELSE IF (#Action = 'U')
BEGIN
INSERT INTO audit_trg
SELECT
i.sanction_status, lr.sanction_status,
GETDATE(), lr.id, 'mytable', #Action
FROM
mytable lr
INNER JOIN
DELETED i ON i.id = lr.id
END
ELSE
BEGIN
INSERT INTO audit_trg
SELECT
lr.sanction_status, i.sanction_status,
GETDATE(), lr.id, 'mytable', #Action
FROM
mytable lr
INNER JOIN
DELETED i ON i.id = lr.id
END
END
and audit_trg table
CREATE TABLE [dbo].[audit_trg]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[old_status] [varchar](50) NULL,
[new_status] [varchar](50) NULL,
[u_datetime] [datetime] NULL,
[ref_id] [int] NULL,
[table_name] [varchar](50) NULL,
[actions] [varchar](50) NULL,
CONSTRAINT [PK_audit_trg]
PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
but I get error after some inserted that is
The target table 'dbo.mytable' of the DML statement cannot have
any enabled triggers if the statement contains an OUTPUT clause
without INTO clause.

View that joins 2 tables of similar structure will not Update (because it contains a derived or constant field)

I'm getting an error:
Msg 4406, Level 16, State 1, Line 5
Update or insert of view or function 'dbo.vwEmployeeAll' failed because it contains a derived or constant field.
Yet, I have no derived or constant in my view.
The columns in my view all exist. It's fairly straightforward in the example below.
-- START TSQL
SET NOCOUNT ON
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'vwEmployeeAll' and TABLE_TYPE = N'VIEW' )
BEGIN
DROP VIEW [dbo].[vwEmployeeAll]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[EmployeeDeprecated]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Employee]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Department' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Department]
END
GO
CREATE TABLE [dbo].[Department](
[DepartmentUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[DepartmentName] [nvarchar](80) NULL,
[CreateDate] [datetime] NOT NULL
)
ALTER TABLE dbo.[Department] ADD CONSTRAINT PK_Department PRIMARY KEY NONCLUSTERED ([DepartmentUUID])
GO
ALTER TABLE [dbo].[Department] ADD CONSTRAINT CK_DepartmentName_Unique UNIQUE ([DepartmentName])
GO
CREATE TABLE [dbo].[Employee] (
/* [EmployeeUUID] [uniqueidentifier] NOT NULL, */
[EmployeeSurrogateKey] int not null IDENTITY(1,2),
[ParentDepartmentUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[SSN] [nvarchar](11) NOT NULL,
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[UpdateDate] [datetime] NOT NULL,
[HireDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.Employee ADD CONSTRAINT PK_Employee PRIMARY KEY NONCLUSTERED (EmployeeSurrogateKey)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT CK_Employee_SSN_Unique UNIQUE (SSN)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT FK_EmployeeToDepartment FOREIGN KEY (ParentDepartmentUUID) REFERENCES dbo.Department (DepartmentUUID)
GO
/*
ALTER TABLE [dbo].[Employee]
ADD CONSTRAINT [CK_Employee_PK_IsOdd] CHECK ( ( [EmployeeSurrogateKey] % 2 ) != 0)
GO
*/
CREATE TABLE [dbo].[EmployeeDeprecated] (
/*[EmployeeDeprecatedUUID] [uniqueidentifier] NOT NULL,*/
[EmployeeDeprecatedSurrogateKey] int not null IDENTITY(2,2),
[ParentDepartmentUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[SSN] [nvarchar](11) NOT NULL,
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[UpdateDate] [datetime] NOT NULL,
[HireDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.[EmployeeDeprecated] ADD CONSTRAINT PK_EmployeeDeprecated PRIMARY KEY NONCLUSTERED (EmployeeDeprecatedSurrogateKey)
GO
ALTER TABLE [dbo].[EmployeeDeprecated] ADD CONSTRAINT CK_EmployeeDeprecated_SSN_Unique UNIQUE (SSN)
GO
ALTER TABLE [dbo].[EmployeeDeprecated] ADD CONSTRAINT FK_EmployeeDeprecatedToDepartment FOREIGN KEY (ParentDepartmentUUID) REFERENCES dbo.Department (DepartmentUUID)
GO
/*
ALTER TABLE [dbo].[EmployeeDeprecated]
ADD CONSTRAINT [CK_EmployeeDeprecated_PK_IsEven] CHECK ( ( [EmployeeDeprecatedSurrogateKey] % 2 ) = 0)
GO
*/
CREATE VIEW dbo.vwEmployeeAll AS
Select
EmployeeSurrogateKey,ParentDepartmentUUID,TheVersionProperty,SSN,LastName,FirstName,CreateDate,UpdateDate,HireDate
from dbo.Employee
UNION --ALL
Select
/* EmployeeSurrogateKey = */
EmployeeDeprecatedSurrogateKey ,ParentDepartmentUUID,TheVersionProperty,SSN,LastName,FirstName,CreateDate,UpdateDate,HireDate
from dbo.EmployeeDeprecated
GO
declare #DepartmentUUID001 uniqueidentifier
select #DepartmentUUID001 = 'DDDDDDDD-0000-0000-0000-000000000101'
declare #DepartmentUUID002 uniqueidentifier
select #DepartmentUUID002 = 'DDDDDDDD-0000-0000-0000-000000000102'
INSERT INTO dbo.Department (DepartmentUUID , DepartmentName , CreateDate )
Select #DepartmentUUID001 , 'Department One' , CURRENT_TIMESTAMP
UNION
Select #DepartmentUUID002 , 'Department Two' , CURRENT_TIMESTAMP
/*
declare #EmployeeUUID001 uniqueidentifier
select #EmployeeUUID001 = 'EEEEEEEE-0000-0000-0000-000000001001'
declare #EmployeeUUID00A uniqueidentifier
select #EmployeeUUID00A = 'EEEEEEEE-0000-0000-AAAA-000000009001'
*/
INSERT INTO dbo.Employee (/*EmployeeUUID,*/ParentDepartmentUUID,SSN,LastName,FirstName,CreateDate,UpdateDate,HireDate)
Select /*#EmployeeUUID001 ,*/ #DepartmentUUID001 , '111-11-1111' , 'Smith', 'John' , CURRENT_TIMESTAMP , CURRENT_TIMESTAMP , '01/01/2001'
INSERT INTO dbo.EmployeeDeprecated(/*EmployeeDeprecatedUUID,*/ParentDepartmentUUID,SSN,LastName,FirstName,CreateDate,UpdateDate,HireDate)
Select /*#EmployeeUUID00A ,*/ #DepartmentUUID002 , '888-88-8888' , 'Jones', 'Mary' , CURRENT_TIMESTAMP , CURRENT_TIMESTAMP , '02/02/2002'
GO
Select * from dbo.vwEmployeeAll
Update dbo.vwEmployeeAll Set UpdateDate = CURRENT_TIMESTAMP
EDIT:
Timestamp throws it for a loop.
Partitioned view 'ViewUpdateableDB.dbo.vwEmployeeAll' is not updatable because table '[ViewUpdateableDB].[dbo].[Employee]' has a timestamp column.
You can't update data in a view that uses a UNION when your primary keys are Identity. You must have a Partitioning Column. Otherwise, how would it know which table to update?
IE, you are using 2 tables that have a primary key on an identity field. They could have a {PK} = 1 in both tables. How would SQL Server know which table to update.
Here is a working example...with "UNION ALL" and a Partitioning Column.
I am posting this, because there is a specific way to get it to work....despite the msdn documentation.
A computation. The column cannot be computed from an expression that
uses other columns. Columns that are formed by using the set operators
UNION, UNION ALL, CROSSJOIN, EXCEPT, and INTERSECT amount to a
computation and are also not updatable.
http://msdn.microsoft.com/en-us/library/ms187956%28v=sql.110%29.aspx
So Steve's answer is correct based on the documentation and under most scenarios, but by using a partitioning-column there is a way to make it work.
The script/example below worked with Developer Edition (which is Enterprise Version without the licensing) and I tested it against SqlExpress ( Microsoft SQL Server 2012 - 11.0.2100.60 (X64)
Express Edition (64-bit) on Windows NT 6.1 (Build 7601: Service Pack 1)
)
Select ##VERSION
-- START TSQL
SET NOCOUNT ON
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'vwEmployeeAll' and TABLE_TYPE = N'VIEW' )
BEGIN
DROP VIEW [dbo].[vwEmployeeAll]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[EmployeeDeprecated]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Employee]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Department' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Department]
END
GO
CREATE TABLE [dbo].[Department](
[DepartmentUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[DepartmentName] [nvarchar](80) NULL,
[CreateDate] [datetime] NOT NULL
)
ALTER TABLE dbo.[Department] ADD CONSTRAINT PK_Department PRIMARY KEY NONCLUSTERED ([DepartmentUUID])
GO
ALTER TABLE [dbo].[Department] ADD CONSTRAINT CK_DepartmentName_Unique UNIQUE ([DepartmentName])
GO
CREATE TABLE [dbo].[Employee] (
/* [EmployeeUUID] [uniqueidentifier] NOT NULL, */
[EmployeeSurrogateKey] int not null IDENTITY(101,2),
[EmployeeTablePartitionOrdinal] int not null,
[ParentDepartmentUUID] [uniqueidentifier] NOT NULL,
/*[TheVersionProperty] [timestamp] NOT NULL,*/
[SSN] [nvarchar](11) NOT NULL,
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[UpdateDate] [datetime] NOT NULL,
[HireDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.Employee ADD CONSTRAINT PK_Employee PRIMARY KEY NONCLUSTERED (EmployeeSurrogateKey,EmployeeTablePartitionOrdinal)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT CK_Employee_SSN_Unique UNIQUE (SSN)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT FK_EmployeeToDepartment FOREIGN KEY (ParentDepartmentUUID) REFERENCES dbo.Department (DepartmentUUID)
GO
/*
ALTER TABLE [dbo].[Employee]
ADD CONSTRAINT [CK_Employee_PK_IsOdd] CHECK ( ( [EmployeeSurrogateKey] % 2 ) != 0)
GO
*/
/*
ALTER TABLE [dbo].[Employee] WITH CHECK ADD CONSTRAINT [CK_Employee_PK_IsOdd]
CHECK ( ( [EmployeeSurrogateKey] % 2 ) != 0)
GO
*/
ALTER TABLE [dbo].[Employee] WITH CHECK ADD CONSTRAINT [CK_EmployeeTablePartitionOrdinal_Is_One]
CHECK ( [EmployeeTablePartitionOrdinal] = 1 )
GO
CREATE TABLE [dbo].[EmployeeDeprecated] (
/*[EmployeeDeprecatedUUID] [uniqueidentifier] NOT NULL,*/
[EmployeeDeprecatedSurrogateKey] int not null IDENTITY(102,2),
[EmployeeTablePartitionOrdinal] int not null,
[ParentDepartmentUUID] [uniqueidentifier] NOT NULL,
/*[TheVersionProperty] [timestamp] NOT NULL,*/ /* Partitioned view 'ViewUpdateableDB.dbo.vwEmployeeAll' is not updatable because table '[ViewUpdateableDB].[dbo].[Employee]' has a timestamp column. */
[SSN] [nvarchar](11) NOT NULL,
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[UpdateDate] [datetime] NOT NULL,
[HireDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.[EmployeeDeprecated] ADD CONSTRAINT PK_EmployeeDeprecated PRIMARY KEY NONCLUSTERED (EmployeeDeprecatedSurrogateKey,EmployeeTablePartitionOrdinal)
GO
ALTER TABLE [dbo].[EmployeeDeprecated] ADD CONSTRAINT CK_EmployeeDeprecated_SSN_Unique UNIQUE (SSN)
GO
ALTER TABLE [dbo].[EmployeeDeprecated] ADD CONSTRAINT FK_EmployeeDeprecatedToDepartment FOREIGN KEY (ParentDepartmentUUID) REFERENCES dbo.Department (DepartmentUUID)
GO
/*
ALTER TABLE [dbo].[EmployeeDeprecated]
ADD CONSTRAINT [CK_EmployeeDeprecated_PK_IsEven] CHECK ( ( [EmployeeDeprecatedSurrogateKey] % 2 ) = 0)
GO
*/
/*
ALTER TABLE [dbo].[EmployeeDeprecated] WITH CHECK ADD CONSTRAINT [CK_EmployeeDeprecated_PK_IsEven]
CHECK ( ( [EmployeeDeprecatedSurrogateKey] % 2 ) = 0)
GO
*/
ALTER TABLE [dbo].[EmployeeDeprecated] WITH CHECK ADD CONSTRAINT [CK_EmployeeTablePartitionOrdinal_Is_Two]
CHECK ( [EmployeeTablePartitionOrdinal] = 2 )
GO
CREATE VIEW dbo.vwEmployeeAll AS
Select
EmployeeSurrogateKey,EmployeeTablePartitionOrdinal,ParentDepartmentUUID,SSN,LastName,FirstName,CreateDate,UpdateDate,HireDate
from dbo.Employee
UNION ALL
Select
EmployeeSurrogateKey =
EmployeeDeprecatedSurrogateKey,EmployeeTablePartitionOrdinal,ParentDepartmentUUID,SSN,LastName,FirstName,CreateDate,UpdateDate,HireDate
from dbo.EmployeeDeprecated
GO
declare #DepartmentUUID001 uniqueidentifier
select #DepartmentUUID001 = 'DDDDDDDD-0000-0000-0000-000000000101'
declare #DepartmentUUID002 uniqueidentifier
select #DepartmentUUID002 = 'DDDDDDDD-0000-0000-0000-000000000102'
INSERT INTO dbo.Department (DepartmentUUID , DepartmentName , CreateDate )
Select #DepartmentUUID001 , 'Department One' , CURRENT_TIMESTAMP
UNION
Select #DepartmentUUID002 , 'Department Two' , CURRENT_TIMESTAMP
/*
declare #EmployeeUUID001 uniqueidentifier
select #EmployeeUUID001 = 'EEEEEEEE-0000-0000-0000-000000001001'
declare #EmployeeUUID00A uniqueidentifier
select #EmployeeUUID00A = 'EEEEEEEE-0000-0000-AAAA-000000009001'
*/
INSERT INTO dbo.Employee (/*EmployeeUUID,*/ParentDepartmentUUID,SSN,LastName,FirstName,CreateDate,UpdateDate,HireDate,EmployeeTablePartitionOrdinal)
Select /*#EmployeeUUID001 ,*/ #DepartmentUUID001 , '111-11-1111' , 'Smith', 'John' , CURRENT_TIMESTAMP , CURRENT_TIMESTAMP , '01/01/2001' , 1
INSERT INTO dbo.EmployeeDeprecated(/*EmployeeDeprecatedUUID,*/ParentDepartmentUUID,SSN,LastName,FirstName,CreateDate,UpdateDate,HireDate,EmployeeTablePartitionOrdinal)
Select /*#EmployeeUUID00A ,*/ #DepartmentUUID002 , '888-88-8888' , 'Jones', 'Mary' , CURRENT_TIMESTAMP , CURRENT_TIMESTAMP , '02/02/2002' , 2
GO
Select * from dbo.vwEmployeeAll
Update dbo.vwEmployeeAll Set UpdateDate = CURRENT_TIMESTAMP
Update dbo.vwEmployeeAll Set LastName = 'Henderson' where EmployeeSurrogateKey = 1
Update dbo.vwEmployeeAll Set UpdateDate = CURRENT_TIMESTAMP where EmployeeSurrogateKey = 2

Resources