Insert values in second table using triggers - sql-server

I have one table called [FridgeTemperture], when any record inserted it should add one value in the new table MpSensors. But records are not being inserted in the new table when a record is inserted.
Error
Explicit value must be specified for identity column in table
'MpSensors' either identity_insert is set to ON or when a replication
user is inserting into a not for replication identity column.
CREATE TRIGGER [dbo].[FridgeTemperature_INSERT]
ON [dbo].[FridgeTemperture]
AFTER INSERT
AS
BEGIN
SET IDENTITY_INSERT MpSensors ON;
SET NOCOUNT ON;
DECLARE #fridge_temp varchar(10)
INSERT INTO MpSensors(fridge_temp)
VALUES(#fridge_temp)
SET IDENTITY_INSERT MpSensors OFF;
END
GO
table schema
CREATE TABLE [dbo].[MpSensors](
[id] [int] IDENTITY(1,1) NOT NULL,
[fridge_temp] [varchar](10) NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[FridgeTemperture](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ShopId] [nvarchar](4) NULL,
[Fridgetemp] [decimal](4, 2) NOT NULL,
[UpdatedDate] [datetime2](7) NOT NULL
GO

You don't need the set identity_insert on if you are not attempting to insert values to the identity column. Also, your current insert statement, if you loose the set identity_insert, will simply inside a single null row for any insert statement completed successfully on the FridgeTemperture table.
When using triggers, you have access to the records effected by the statement that fired the trigger via the auto-generated tables called inserted and deleted.
I think you are after something like this:
CREATE TRIGGER [dbo].[FridgeTemperature_INSERT]
ON [dbo].[FridgeTemperture]
AFTER INSERT
AS
BEGIN
INSERT INTO MpSensors(fridge_temp)
SELECT CAST(Fridgetemp as varchar(10))
FROM inserted
END
Though I can't really see any benefit of storing the same value in two different places, and in two different data types.
Update
Following our conversation in the comments, you can simply use an update statement in the trigger instead of an insert statement:
UPDATE MpSensors
SET fridge_temp = (
SELECT TOP 1 CAST(Fridgetemp as varchar(10))
FROM inserted
ORDER BY Id DESC
)
This should give you the latest record in case you have an insert statement that inserts more than a single record into the FridgeTemperture table in a single statement.

create TRIGGER [dbo].[FridgeTemperature_INSERT]
ON [dbo].[FridgeTemperture]
AFTER INSERT
AS
BEGIN
UPDATE MpSensors
SET fridge_temp = CAST(Fridgetemp as varchar(10))
FROM inserted
END

You need to use Select statement with CAST as [fridge_temp] is varchar in MpSensors table in Trigger. Try like this:
CREATE trigger <table_name>
ON <table_name>
AFTER Insert
AS
BEGIN
INSERT INTO <table_name>(column_name)
Select CAST(column_name as varchar(10))
FROM inserted
END
The inserted table stores copies of the affected rows during INSERT and UPDATE statements. During an insert or update transaction, new rows are added to both the inserted table and the trigger table. The rows in the inserted table are copies of the new rows in the trigger table.

Related

Inserting to table having issue - Explicit value must be specified for identity column in table

I'm getting ready to release a stored procedure that gets info from other tables, does a pre-check, then inserts the good data into a (new) table. I'm not used to working with keys and new tables as much, and my insert into this new table I'm creating is having this error message having to do with the insert/key:
Msg 545, Level 16, State 1, Line 131
Explicit value must be specified for identity column in table 'T_1321_PNAnnotationCommitReport' either when IDENTITY_INSERT is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity column.
BEGIN
...
BEGIN
IF NOT EXISTS (SELECT * FROM sys.tables where name = N'T_1321_PNAnnotationCommitReport')
BEGIN
CREATE TABLE T_1321_PNAnnotationCommitReport (
[id] [INT] IDENTITY(1,1) PRIMARY KEY NOT NULL, --key
[progressnote_id] [INT] NOT NULL,
[form_id] [INT] NOT NULL,
[question_id] [INT],
[question_value] [VARCHAR](max),
[associatedconcept_id] [INT],
[crte_date] [DATETIME] DEFAULT CURRENT_TIMESTAMP,
[create_date] [DATETIME] --SCHED_RPT_DATE
);
print 'test';
END
END --if not exists main table
SET IDENTITY_INSERT T_1321_PNAnnotationCommitReport ON;
...
INSERT INTO dbo.T_1321_PNAnnotationCommitReport--(progressnote_id,form_id,question_id,question_value,associatedconcept_id,crte_date, create_date) **I tried with and without this commented out part and it's the same.
SELECT progressnote_id,
a.form_id,
question_id,
questionvalue,
fq.concept_id,
getdate(),
a.create_date
FROM (
SELECT form_id,
progressnote_id,
R.Q.value('#id', 'varchar(max)') AS questionid,
R.Q.value('#value', 'varchar(max)') AS questionvalue,
create_date
FROM
#tableNotes t
OUTER APPLY t.form_questions.nodes('/RESULT/QUESTIONS/QUESTION') AS R(Q)
WHERE ISNUMERIC(R.Q.value('#id', 'varchar(max)')) <> 0
) a
INNER JOIN [CKOLTP_DEV]..FORM_QUESTION fq ON
fq.form_id = a.form_id AND
fq.question_id = a.questionid
--select * from T_1321_PNAnnotationCommitReport
SET IDENTITY_INSERT T_1321_PNAnnotationCommitReport OFF;
END
Any ideas?
I looked at some comparable inserts we do at work, insert into select and error message, and insert key auto-incremented, and I think I'm doing what they do. Does anyone else see my mistake? Thanks a lot.
To repeat my comment under the question:
The error is literally telling you the problem. You turn change the IDENTITY_INSERT property to ON for the table T_1321_PNAnnotationCommitReport and then omit the column id in your INSERT. If you have enabled IDENTITY_INSERT you need to supply a value to that IDENTITY, just like the error says.
We can easily replicate this problem with the following batches:
CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1),
SomeValue varchar(20));
GO
SET IDENTITY_INSERT dbo.MyTable ON;
--fails
INSERT INTO dbo.MyTable (SomeValue)
VALUES('abc');
GO
If you want the IDENTITY value to be autogenerated, then leave IDENTITY_INSERT set to OFF and omit the column from the INSERT (like above):
SET IDENTITY_INSERT dbo.MyTable OFF; --Shouldn't be needed normally, but we manually changed it before
--works, as IDENTITY_INSERT IS OFF
INSERT INTO dbo.MyTable (SomeValue)
VALUES('abc');
If you do specifically want to define the value for the IDENTITY, then you need to both set IDENTITY_INSERT to ON and provide a value in the INSERT statement:
SET IDENTITY_INSERT dbo.MyTable ON;
--works
INSERT INTO dbo.MyTable (ID,SomeValue)
VALUES(10,'def');
GO
SELECT *
FROM dbo.MyTable;
IDENTITY_INSERT doesn't mean "Get the RDBMS to 'insert' the value" it means that you want to want to tell the RDBMS what value to INSERT. This is covered in the opening sentence of the documentation SET IDENTITY_INSERT (Transact-SQL):
Allows explicit values to be inserted into the identity column of a table.
(Emphasis mine)

Reinsert primary key in the same record

I need to insert records into a production table. The problem is that one of the fields needs to be the same value as the primary key.
In the example below, the Insert query is dropping '99' into [AlsoMyID]. But that's just a placeholder. It needs to be whatever value is going into [MyID].
How do I write the Insert query so that the system will add the same PK value to both [MyID] and [AlsoMyID]?
Drop table #mylittletable
Create table #Mylittletable (
[MyID] int IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[AlsoMyID] int,
[ActualData] varchar(1))
Select * from #Mylittletable
Insert into #Mylittletable values (99,'x')
Select * from #Mylittletable
If you're interested in the background, the developer is using AlsoMyID as a linking field so any number of records can be linked together using the original primary key value. That said, I have no control over the table structure.
Firstly, you cannot specify the value for identity column unless you use set identity_insert on. so according to your requirement, you need to insert the same value to AlsoMyID as MyID.
You can work it out as flowing:
insert into Mylittletable
select ##IDENTITY+1,'1'
With this trigger on the table you can insert anything on the alsoMyID-column and that will be overwritten with what get's set in the myID-column.
create trigger tr_Mylittletable ON Mylittletable
AFTER INSERT AS
BEGIN
declare #ID int = (select MyID from inserted)
update Mylittletable set AlsoMyID = #ID where MyID = #ID
END
NOTE: This only works when making inserts of one line at a time!

Null values INSERTED in trigger

I want to copy content of one table to another table in the same database.
For this I wrote trigger on source table which triggered on AFTER INSERT UPDATE, there are 2 uniqueidentifier fields in the table which generates values based on newid() as default binding. Based on this uniqueidentifier I am checking whether the record is present on the destination table or not if present then it will update and if not present then insert dataset into the table.
Problem is when i insert a new record the INSERTED in trigger give me NULL values for the uniqueidentifier fields.
In may case only one row is either update or insert so cursor is not used.
Below is my code, I am getting null values in #OriginalTable_MoveDataUID and #OriginalTable_ProcedureUID. Both the MoveDataUID and ProcedureUID are uniqueidentifier fileds.
Please share your thoughts or any alternative for this.
ALTER TRIGGER [dbo].[spec_ref_movedata_procedures_ToUpdate]
ON [dbo].[spec_ref_movedata_procedures]
AFTER INSERT, UPDATE
AS
BEGIN
SET XACT_ABORT ON
BEGIN DISTRIBUTED TRANSACTION
DECLARE #OriginalTable_MoveDataUID NVarchar (100)
DECLARE #OriginalTable_ProcedureUID NVarchar (100)
DECLARE #PresentInHistoryYesNo int
SELECT #OriginalTable_MoveDataUID= MoveDataUID,#OriginalTable_ProcedureUID=ProcedureUID FROM INSERTED
-- inserted for checking purpose
INSERT INTO ERP_Test_NK_spec_ref_movedata_procedures_history_2 (MovedataUID,ProcedureUID) VALUES
(#OriginalTable_MoveDataUID,#OriginalTable_ProcedureUID)
SELECT #PresentInHistoryYesNo = count(*) from spec_ref_movedata_procedures_history WHERE MoveDataUID=#OriginalTable_MoveDataUID AND ProcedureUID=#OriginalTable_ProcedureUID
IF #PresentInHistoryYesNo = 0
BEGIN
-- insert opertions
print 'insert record'
END
ELSE IF #PresentInHistoryYesNo = 1
BEGIN
-- update opertions
print 'update record'
END
COMMIT TRANSACTION
SET XACT_ABORT OFF
END
Instead of using variables, you could do this:
INSERT INTO ERP_Test_NK_spec_ref_movedata_procedures_history_2 (MovedataUID,ProcedureUID)
SELECT MoveDataUID,ProcedureUID FROM INSERTED

fail to insert into two tables via stored procedures

I'm trying to insert into two tables at the same time via stored procedure but it writes to only one table and fail to the other.
ALTER PROCEDURE [dbo].[insert_emp_pics]
#EmpName nvarchar(100),
#Nationality nvarchar(30),
#PassportPic nvarchar(100),
#Pic nvarchar(100)
AS
Begin
set nocount on;
DECLARE #ID int,
#Emp_ID int
insert into Employee (EmpName,Nationality)
values (#EmpName,#Nationality)
select #ID = ##IDENTITY
insert into DatePics
(PassportPic,Pic)
values
(#PassportPic ,#Pic)
select #Emp_ID = ##IDENTITY
end
There is relation between two tables
first table [Employee] PK ID
second table [DatePics] FK Emp_ID
this is the error message after executing this statement.
Cannot insert the value NULL into column 'Emp_ID', table 'QTecTest.dbo.DatePics';
column does not allow nulls. INSERT fails.
You need to insert the new Emp_Id as a Foreign Key to DatePics (and assuming both tables have identity columns):
insert into Employee (EmpName,Nationality)
values (#EmpName,#Nationality);
set #EMP_ID = SCOPE_IDENTITY();
insert into DatePics (PassportPic,Pic, Emp_ID)
values (#PassportPic ,#Pic, #EmpID);
set #DatePicsID = SCOPE_IDENTITY();
Also, please use SCOPE_IDENTITY over ##IDENTITY - ##Identity is vulnerable to issues where a Trigger also creates an new (unrelated) identity.
A column declared as primary key cannot have NULL values.
In your stored procedure you are not supplying value to Emp_ID column and so Insert fails.
If you want to automatically insert values in that column make it as IDENTITY column also

Dropping Tables within an AFTER INSERT Trigger

I am looking for suggestions on how to handle incoming data from a C# client app that sends via System.Data.SqlClient.SqlBulkCopy. The original intent was to maintain all data sent via the app into our sql server where the data would be 'massaged'. To keep things secure, data is sent to write only tables where an AFTER INSERT trigger will copy to another table and delete incoming.
Simple Example:
ALTER TRIGGER [dbo].[FromWeb_To_MyTable] ON [dbo].[_FromWeb_MyTable]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[MyTable]([MyTableID],[MemberID],[LocationID],[ODBCID],[InsertDateTime])
SELECT i.[MyTableID],i.[MemberID],i.[LocationID],i.[ODBCID],i.[InsertDateTime]
FROM Inserted i;
DELETE FROM _FromWeb_MyTable
WHERE [MyTableID] IN (SELECT i.[MyTableID] FROM Inserted i);
END
Now I am going to be using a bit differently and need to delete everything in the 'go to' table. My largest table will be around 350,000 records. I intend to DROP and re-CREATE said table like so:
(this method IS working fine see my questions below)
ALTER TRIGGER [dbo].[FromWeb_To_MyTable] ON [dbo].[_FromWeb_MyTable]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS(SELECT [name] FROM sys.TABLES WHERE [name] = 'MyTable') DROP TABLE [dbo].[MyTable];
CREATE TABLE [dbo].[MyTable] (
[MyTableID] [int] NOT NULL,
[MemberID] [varchar](6) NOT NULL,
[LocationID] [varchar](50) NOT NULL,
[ODBCID] [varchar](50) NOT NULL,
[InsertDateTime] [datetime] NOT NULL
) on [PRIMARY];
INSERT INTO [dbo].[MyTable] ( [MyTableID], [MemberID],[LocationID],[ODBCID],[InsertDateTime] )
SELECT i.[MyTableID],i.[MemberID],i.[LocationID],i.[ODBCID],i.[InsertDateTime]
FROM Inserted i;
DELETE FROM _FromWeb_MyTable
WHERE [MyTableID] IN (SELECT [MyTableID] FROM Inserted);
END
Does anyone see any problems with this method? Any different suggestions? Can someone explain when and how to index the newly recreated table?
Since you reuse your table instead of dropping and re-creating it just use TRUNCATE.
ALTER TRIGGER dbo.FromWeb_To_MyTable ON dbo._FromWeb_MyTable
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
TRUNCATE TABLE dbo.MyTable;
INSERT INTO dbo.MyTable (MyTableID, MemberID,LocationID,ODBCID,InsertDateTime)
SELECT i.MyTableID,i.MemberID,i.LocationID,i.ODBCID,i.InsertDateTime
FROM Inserted i;
DELETE FROM _FromWeb_MyTable
WHERE MyTableID IN (SELECT MyTableID FROM Inserted);
END

Resources