I created a trigger that performs a check and automatically populates data into 2 tables. Only what happens the following error :
IDENTITY_INSERT is already ON for table 'X'. Cannot perform SET operation for table 'Y'.
I found this while researching the error:
"At any time, only one table in a session can have the IDENTITY_INSERT property set to ON.”
So the fix was easy:
SET IDENTITY_INSERT Table1 ON
-- insert statements for table1
SET IDENTITY_INSERT Table1 OFF
SET IDENTITY_INSERT Table2 ON
-- insert statements for table2
SET IDENTITY_INSERT Table2 OFF
SET IDENTITY_INSERT Table3 ON
-- insert statements for table3
SET IDENTITY_INSERT Table3 OFF
But as the data is populated via trigger is not possible to do so.
Does anyone have a solution to my problem please?
I apologize.
Thank you all.
Trigger-----
CREATE TRIGGER Alert ON registos AFTER INSERT AS
BEGIN
DECLARE #comp decimal = 0
DECLARE #id_sensores_em_alerta decimal
DECLARE #tempmin decimal = 0
DECLARE #current_max_idAlarme int = (SELECT MAX(IdAlarme) FROM alarmes)
DECLARE #maxidAlarme int
DECLARE #temp decimal = (SELECT s.lim_inf_temp from sensores s JOIN inserted i ON s.idSensor=i.idSensor )
-- Insert into alarmes from the inserted rows if temperature less than tempmin
INSERT alarmes (IdAlarme, descricao_alarme,data_criacao, idRegisto)
SELECT
ROW_NUMBER() OVER (ORDER BY i.idRegisto) + #current_max_idAlarme, 'temp Error', GETDATE(), i.idRegisto
FROM
inserted AS i
WHERE
i.Temperatura < #temp
SET #maxidAlarme = (SELECT MAX(IdAlarme) FROM alarmes)
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme)
SELECT i.idSensor, #maxidAlarme, GETDATE()
FROM inserted i
SET #comp += 1;
SET #id_sensores_em_alerta=1;
SET #id_sensores_em_alerta = (SELECT MAX(id_sensores_em_alerta) FROM sensores_em_alerta)
INSERT INTO sensores_em_alerta(id_sensores_em_alerta, idSensor, idAlarme, data_registo, numerosensoresdisparados)
SELECT #id_sensores_em_alerta, i.idSensor, #maxidAlarme, GETDATE(), #comp
FROM inserted i
end
DataBase----
I had a similar problem but it did not involve table triggers. I was running a script that refreshes data for multiple tables and I hit a foreign key reference error.
According to MSDN:
At any time, only one table in a session can have the IDENTITY_INSERT
property set to ON.
To resolve this, I ran SET IDENTITY_INSERT [dbo].[table_name] OFF for each table I was trying to insert into. Then I was able to refresh my tables again after I corrected the reference error.
Edit: I should also mention that you can just disconnect and then reconnect to reset your session.
Allow SQL Server to insert the identity values automatically for you. Since this is a trigger, there could multiple rows being inserted at a time. For one row inserts, you can use SCOPE_IDENTITY() function (http://msdn.microsoft.com/en-us/library/ms190315.aspx) to retrieve the identity value of your last inserted row. However, since we could have multiple rows inserted in a trigger, we will use the OUTPUT clause (http://msdn.microsoft.com/en-us/library/ms177564.aspx) to get back a list of the inserted IdAlarme values for each idRegisto.
I'm assuming that alarmes.IdAlarme and sensores_em_alerta.id_sensores_em_alerta are the two identity fields in this trigger. If that is the case, then this should work:
CREATE TRIGGER Alert ON registos AFTER INSERT AS
BEGIN
DECLARE #comp decimal = 0
DECLARE #id_sensores_em_alerta decimal
DECLARE #tempmin decimal = 0
DECLARE #temp decimal = (SELECT s.lim_inf_temp from sensores s JOIN inserted i ON s.idSensor=i.idSensor )
DECLARE #tblIdAlarme TABLE (idRegisto int not null, IdAlarme int not null);
-- Insert into alarmes from the inserted rows if temperature less than tempmin
-- IdAlarme is identity field, so allow SQL Server to insert values automatically.
-- The new IdAlarme values are retrieved using the OUTPUT clause http://msdn.microsoft.com/en-us/library/ms177564.aspx
INSERT alarmes (descricao_alarme,data_criacao, idRegisto)
OUTPUT inserted.idRegisto, inserted.IdAlarme INTO #tblIdAlarme(idRegisto, IdAlarme)
SELECT descricao_alarme = 'temp Error', data_criacao = GETDATE(), i.idRegisto
FROM inserted AS i
WHERE i.Temperatura < #temp
;
--It looks like this table needs a PK on both idSensor and idAlarme fields, or else you will get an error here
-- if an alarm already exists for this idSensor.
INSERT INTO sensores_tem_alarmes(idSensor,idAlarme,dataAlarme)
SELECT i.idSensor, a.IdAlarme, dataAlarme = GETDATE()
FROM inserted i
INNER JOIN #tblIdAlarme a ON i.idRegisto = a.idRegisto
;
--not sure what this is doing?? Will always be 1.
SET #comp += 1;
--id_sensores_em_alerta is an identity field, so allow SQL Server to insert values automatically
INSERT INTO sensores_em_alerta(idSensor, idAlarme, data_registo, numerosensoresdisparados)
SELECT i.idSensor, a.IdAlarme, data_registo = GETDATE(), numerosensoresdisparados = #comp
FROM inserted i
INNER JOIN #tblIdAlarme a ON i.idRegisto = a.idRegisto
;
END
Related
How to insert 100 rows to the following table using a single query?
CREATE TABLE #TEST1 (TEST_ID INT IDENTITY(1,1))
I tried below code
DECLARE #numRows int,#i int
SET #numRows = 100
SET #i=1
WHILE #i<#numRows
begin
INSERT #TEST1 SELECT TOP 1 1 FROM sysobjects a
SET #i=#i+1
end
but it is not working.
You can try the following query
CREATE TABLE #TEST1 (TEST_ID INT IDENTITY(1,1))
SET IDENTITY_INSERT #TEST1 ON;
DECLARE #numRows int,#i int
SET #numRows = 100
SET #i=1
WHILE #i<#numRows
BEGIN
INSERT #TEST1(TEST_ID) SELECT #i
SET #i=#i+1
END
SET IDENTITY_INSERT #TEST1 OFF;
SELECT * FROM #TEST1
DROP TABLE #TEST1
Thanks
Offhand, I cannot think of a way of doing this with one statement. You could use the table master.dbo.spt_values:
set identity_insert #test1 off;
insert into #test1 (test_id)
select top (100) row_number() over (order by (select null))
from master.dbo.spt_values;
set identity_insert #test1 on;
The specific problem is that select needs to return something, and that something can't be a non-value for a non-column. And the alternative values syntax only inserts one row at a time.
You might be better off doing:
create table #test1 (
test_id int identity(1, 1) primary key,
dummary varchar(1)
);
insert into #test1 (dummy)
select top (100) cast(NULL as varchar(1))
from master.dbo.spt_values;
This uses a minimal amount of space, because a NULL varchar() only occupies space for the NULL bit.
For your code, default values will work:
WHILE #i<#numRows
begin
INSERT #TEST1 DEFAULT VALUES
SET #i=#i+1
end
This option does not require set identity_insert on.
Using merge will allow you to use default values for multiple rows:
MERGE INTO #TEST1
USING
(
SELECT TOP 100 *
FROM sys.objects
) S
ON 1 = 0
WHEN NOT MATCHED THEN
INSERT
DEFAULT VALUES;
(Thanks again to Martin Smith for the merge trick on this SO post)
The advantage here is that this does not assume anything about the identity column, or even the existence of one - it can be used to insert the default value to whatever columns you have on the table, be it a single int identity(1, 1), or even many columns.
You can see a live demo on rextester.
Or just simply this:
INSERT INTO #Temp1 DEFAULT VALUES
GO 100
Run this in SQL Server Management Studio and you'll get 100 rows inserted into #Temp1
Use code below :
//replace server namd and instance with name in login window for SQL Server Management Studio (ssms)
//replace database name wit you database
string connectionString = "Server=myServerName\myInstanceName;Database=myDataBase;Trusted_Connection=True;";
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
for (int i = 0; i < 100; i++)
{
string query = string.Format("INSERT INTO [dbo].[#TEST1] (TEST_ID) VALUES ({0})", i);
cmd.CommandText = query;
cmd.ExecuteNonQuery();
}
I have a scenario where i have to update record in database table from another database table based on recently updated record.
if record is new insert statement will fire
if record is updated Update statement will fire
here the problem is we don't know number of table return by query
as well as column name.
here is code
DECLARE #RowsToProcess int
DECLARE #CurrentRow int
declare #tablenames varchar(100)
DECLARE #sampleTable TABLE(RowID int not null primary key identity(1,1), tablename varchar(100),last_user_update datetime)
insert into #sampleTable SELECT [TableName] = OBJECT_NAME(object_id),last_user_update
FROM sys.dm_db_index_usage_stats
WHERE database_id = DB_ID('DATABASE')
select * from #sampleTable
SET #RowsToProcess=##ROWCOUNT
print #RowsToProcess
SET #CurrentRow=0
WHILE #CurrentRow<#RowsToProcess
BEGIN
SET #CurrentRow=#CurrentRow+1
SELECT #tablenames= tablename from #sampleTable
WHERE RowID=#CurrentRow
print #tablenames
EXEC('INSERT INTO '+ 'SM_' + #tablenames +' SELECT * FROM '+#tablenames + 'Where flag = NULL' )
END
In SQL Server, you can use triggers. SQL Server triggers can fire on insert, on update, on delete or instead of insert, etc.
You may get started using this lesson
In my C# application I'm executing multiple update queries to manipulate data in the database table. E.g. replace a specific character set into a different character set, insert new characters and remove characters. When a query like this has executed I want to do two things. Get the total rowcount of the affected rows and get a row_number() result set of the affected rows. The first thing is quite simple and is working already. The second thing however is something I haven't been able to figure out yet.
Here is an example of a query that I might use when I'm manipulating data:
UPDATE myTable
SET myColumn = STUFF(myColumn, fromCharPos, toCharPos,
REPLACE(SUBSTRING(myColumn, fromCharPos, toCharPos), charToReplace, charReplacement))
WHERE LEN(myColumn) >= fromCharPos;
This query replaces (on all the cells of a column) a character set with another character set within a specified character range.
When this query has executed I want to get a result set of row numbers from the affected rows. Anyone know how I'm able to implement this?
Some things to consider:
It has to work on atleast SERVER version 2005 and up.
The UPDATE statements are executed within a transaction
If anything is unclear, please comment below so I'm able to improve my question.
Edit:
I noticed that it is not quite clear what I want to achieve.
Lets say we have a set of data that looks like this:
34.56.44.12.33
32.44.68
45.22.66.33.77
44.42.44
66.44.22.44.45
00.22.78
43.98.34.65.33
Now I want to replace the dots with an underscore between character position 9 to 12. That means that only these rows will be affected by the query:
34.56.44.12.33 <--
32.44.68
45.22.66.33.77 <--
44.42.44
66.44.22.44.45 <--
00.22.78
43.98.34.65.33 <--
The thing I want to achieve is to get a row number result set of the affected rows. In my example that will be a result set like this:
Row_number()
1
3
5
7
This may help you..
CREATE TABLE #updatetablename
(excolumn VARCHAR(100))
INSERT INTO #updatetablename
VALUES ('34.56.44.12.33'),
('32.44.68'),
('45.22.66.33.77'),
('44.42.44'),
('66.44.22.44.45'),
('00.22.78'),
('43.98.34.65.33')
DECLARE #temp TABLE
(excolumn VARCHAR(100))
DECLARE #temp1 TABLE
(row_num INT,excolumn VARCHAR(100))
INSERT INTO #temp1
SELECT Row_number()OVER (ORDER BY excolumn),*
FROM #updatetablename
UPDATE #updatetablename
SET excolumn = Replace(excolumn, '.', '_')
output deleted.excolumn
INTO #temp
WHERE Len(excolumn) > 12
SELECT b.row_num AS updatedrows,
a.excolumn
FROM #temp a
JOIN #temp1 b
ON a.excolumn = b.excolumn
Updated
declare #table table(val varchar(500))
insert into #table values
('34.56.44.12.33'),
('32.44.68'),
('45.22.66.33.77'),
('44.42.44'),
('66.44.22.44.45'),
('00.22.78'),
('43.98.34.65.33')
--select * from #table
declare #temp table(rowid int,val varchar(500), createdate datetime)
insert into #temp
select ROW_NUMBER () over(order by val), val, GETDATE() from #table
declare #rowEffectedCount int = 0
--select ROW_NUMBER () over(order by val), val, GETDATE() from #table WHERE CHARINDEX( '.',val,9 ) > 0
UPDATE #table
SET val =
REPLACE(SUBSTRING(val, CHARINDEX( '.',val,9 ), LEN(val)), ',', '_' )
WHERE CHARINDEX( '.',val,9 ) > 0
set #rowEffectedCount = ##ROWCOUNT
select #rowEffectedCount roweffected ,* from #temp t1
where val not in (
select val from #table )
Old one
Its quite simple as my understanding.
You just add a one select query of your update query. read the comment for more understand
declare #rowEffectedCount int = 0
--you can use a temp table or permanet history table to take each work of portion.
--one thing to be carefull as structure is same or only save the pk , then no issue
--create table tempRowcount and insert the statement with the same where query, which filter the same data.
declare #t table(id int, createdate datetime)
select * into #t from myTable WHERE LEN(myColumn) >= fromCharPos
--or only pk
select id into #t from myTable WHERE LEN(myColumn) >= fromCharPos
--now update the
UPDATE myTable
SET myColumn = STUFF(myColumn, fromCharPos, toCharPos,
REPLACE(SUBSTRING(myColumn, fromCharPos, toCharPos), charToReplace, charReplacement))
WHERE LEN(myColumn) >= fromCharPos;
select * from #t
--finally delete or truncate or drop the table(if you use permanent table)
I have two tables Employee and Employee Log, I created a trigger after insert, I have no problem with my after insert trigger using entities or values from employee, to insert directly to Log table, but how would I insert value from another table? like Admin_ID. I want a log table with transaction, datetime and who created.
Thank you.
CREATE TRIGGER emp_log_af AFTER INSERT ON emp
FOR EACH ROW
BEGIN
INSERT INTO emp_log (action,id,ts, ad_id)
VALUES('create',NEW.id,NOW());
END;
its not possible with trigger what i did was get the max(id) to do that i created a stored procedure.
DELIMITER $$
CREATE PROCEDURE sp_insert_user_log
(
IN ia Varchar(12),
IN ie INT,
IN ix datetime
)
BEGIN
DECLARE id INT DEFAULT 0;
SELECT MAX(user_id) INTO id FROM user ORDER BY user_id DESC LIMIT 1;
BEGIN
INSERT INTO `user_log`(`action`, `user_id`, `employee_id`, `ts`) VALUES (ia, id, ie, ix);
END;
END$$
DELIMITER ;
DELIMITER $$
i want get value of field after update,
for example i have two table
table1: ID Price UserID type
table2: IDLog ID(FK table1) OldPrice
and i update Price in table 1:
UPDATE table1
SET Price = '1111'
WHERE TYPE = 1
now i want befor every update get value ID table1 and insert into table2,
how i get value every field??
IMHO FOR UPDATE TRIGGER is the way to go. That way you can contain all logging logic inside your DB.
Better way to do it is using trigger on table1 (SQL Server side of course).
CREATE TRIGGER table1_update ON table1 FOR UPDATE
AS
BEGIN
INSERT INTO table2 (IDLog, OldPrice)
SELECT ID, Price
FROM deleted
INNER JOIN inserted ON
deleted.ID = inserted.ID
deleted.Price <> inserted.Price
END
You can use output clause:
update table1
output inserted.ID into table2
set Price='1111' where type=1
You can insert data to table2 before updating.
INSERT INTO table2
SELECT ID, Price from table1
WHERE TYPE = 1
--Update table1 after inserting
UPDATE table1
SET Price = '1111'
WHERE TYPE = 1
Other way to do is to create an update trigger for table1, which inserts the updated data to table2.