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 $$
Related
I'd like to perform an SQL query on a data table and return records with IDs that match any one of the IDs in a particular list (which would be passed in as a parameter to the SQL TableAdapter query). This ID which is being checked is a foreign key in the table. The following is the code am I using, only including what is relevant:
SELECT BookingID, DogID
FROM Booking
WHERE DogID IN (...)
Ideally, I'd like to be able to pass in a list of type string.
You can pass id as , separated string and use User Define function to split that:
try below:
UDF
CREATE FUNCTION [dbo].[Udf_stringtolist] (#List NVARCHAR(max),
#Delimeter NVARCHAR(10))
returns #tmpListTable TABLE (
value NVARCHAR(max))
AS
BEGIN
DECLARE #DelimPosition INT
SELECT #DelimPosition = Charindex(#Delimeter, #List)
WHILE #DelimPosition > 0
BEGIN
INSERT INTO #tmpListTable
(value)
VALUES (Cast(Ltrim(Rtrim(LEFT(#List, #DelimPosition - 1))) AS
VARCHAR(
100)))
SELECT #List = RIGHT(#List, Len(#List) - #DelimPosition),
#DelimPosition = Charindex(#Delimeter, #List)
END
IF Len(#List) > 0
INSERT INTO #tmpListTable
(value)
VALUES (Cast(Ltrim(Rtrim(#List)) AS VARCHAR(100)))
RETURN
END
Use the function:
DECLARE #idList NVARCHAR(max)=',1,2,3,4,5,6';
SELECT bookingid,
dogid
FROM booking
WHERE dogid IN (SELECT *
FROM [dbo].[Udf_stringtolist] (#idList, ',')
ORDER BY 1)
There are 2 ways.
Comma separated ids - which will lead to performance issue while split it
XML - is best approach.
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
ALTER PROCEDURE [dbo].[ProcTeamInfoById]
(#id INT,
#txtName VARCHAR(50),
#phone VARCHAR(100),
#contactname VARCHAR(100),
#address VARCHAR(300),
#email VARCHAR(100),
#captain VARCHAR(100),
#requirements VARCHAR(50))
AS
BEGIN
IF #id = -1
BEGIN
DECLARE #teamID VARCHAR(MAX);
INSERT INTO TeamDetails(TeamName, Phone, ContactName, Address, Email, captain)
VALUES (#txtName, #phone, #contactname, #address, #email, #captain)
SET #teamID = SCOPE_IDENTITY();
// Here now I need to add to different table...
// checkbox checked values
INSERT INTO teamrequirements (teamid, requirement, value)
VALUES (#teamID, #requirements, 1)
// Here I am getting 1, bats, Gloves, 1
END
ELSE
UPDATE TeamDetails
SET TeamName = #txtName, Phone = #phone,
ContactName = #contactname,
Address = #address, Email = #email,
WHERE TeamId = #id
END
I need like this how to modify stored procedure
1, bats,gloves,1
I need to insert as
1 bats 1
2 gloves1
If I need to update the above it should be like
1 bats 1
If I updating with no values it should be like
1 '' ''
My stored procedure inserts into two tables. While adding into teamrequirements table, I need to split one column value into multiple columns where I commented. I need to modify the stored procedure to insert into multiple columns and records
in the teamrequirements table.
How to do it?
While adding a team is added into the teamdetails table, and I have checkbox like Requirements if I check that I can select another two checkboxes, when both checkboxes are checked, two records to be inserted in teamrequirements, example , i wil have teamid, requirement, value...example 1,bats,Gloves,1 this should insert as 2 records Like
12,1 bat , 1 // 12 is record id in teamrequirements
13,1,Gloves , 1 // 13 is record id in teamrequirements
Please help...
What if it is Update in the same procedure ..
update teamrequirements set requirement= #reuirement , value = 1 where teamid = #id in this case , if i add those two records bats gloves in database i am adding records , what if i need to clear those added records using update statement in the same procedure
You can use any of the split function over the internet or create your own and use it. Below code has been written according to split function in FnSplitString.
You created a split function in your database. This function will return 1 or more values from your string provided. This is your #requirements variable.
IF(LEN(#requirements) > 0)
BEGIN
INSERT INTO teamrequirements (teamid, requirement, value)
SELECT #teamID, splitdata, '1' FROM dbo.[fnSplitString](#requirements,',')
END
ELSE
BEGIN
INSERT INTO teamrequirements (teamid, requirement, value)
VALUES (#teamID, '', '')
END
SQL 2016:
JSON support is there now. So, you can pass string as json and take 2 values into key value table, and insert it directly. No need to split.
FOR UPDATE:
You can take this split string data in a table variable. Update data from table variable as source into main table, with a JOIN condition.
DECLARE #id INT = 40
DECLARE #data TABLE
(
Id INT,
Requirement VARCHAR(50),
Value INT
)
DECLARE #requirements VARCHAR(50) = 'bat,gloves,ball'
INSERT INTO #data
SELECT #id, splitdata, 1 FROM dbo.[fnSplitString](#requirements,',')
SELECT * FROM #data
-- SOMETHING LIKE THIS CAN BE YOUR UPDATE QUERY
UPDATE a SET
value = b.Value
FROM teamrequirements a INNER JOIN #data b ON a.id = b.Id
and a.requirement = b.Requirement
MERGE SAMPLE:
MERGE teamrequirements AS TARGET
USING #data AS SOURCE
ON TARGET.id = SOURCE.Id AND TARGET.requirement = SOURCE.Requirement
--When records are matched, update
--the records if there is any change
WHEN MATCHED THEN
UPDATE SET TARGET.value = SOURCE.Value
--When no records are matched, insert
--the incoming records from source
--table to target table
WHEN NOT MATCHED BY TARGET THEN
INSERT (teamid, requirement, value)
VALUES (SOURCE.Id, SOURCE.Requirement, SOURCE.Value);
First, it would be better to use table valued parameters for this.
Without that, you can split the string (this demo uses delimitedsplit8k by Jeff Moden) , and you could use merge to handle changes. It makes sense to move this into its own procedure and call that procedure from your current one.
TL;DR: rextester demo: http://rextester.com/PVX88970
The TeamRequirements_Merge procedure:
create procedure dbo.TeamRequirements_Merge (
#TeamId int
, #requirements varchar(8000)
) as
begin;
set nocount, xact_abort on;
/* it would be much better to use table valued parameters for this */
;with t as (
select TeamId, Requirement, Value
from TeamRequirements
where TeamId = #TeamId
)
, s as (
select
TeamId = #TeamId
, Requirement = coalesce(s.item,'') -- since you want blanks
, Value = 1
from dbo.[delimitedsplit8K](#requirements,',') s
)
merge into t with (holdlock)
using s
on t.TeamId = s.TeamId
and t.Requirement = s.Requirement
when matched and t.value <> s.value
then update set t.value = s.value
when not matched by target
then insert (TeamId, Requirement, Value)
values (s.TeamId, s.Requirement, s.Value)
when not matched by source
then delete
--output $Action, inserted.*, deleted.* /* for testing */
;
end;
go
The revised ProcTeamInfoById procedure:
create procedure [dbo].[ProcTeamInfoById] (
#id int
, #txtName varchar(50)
, #phone varchar(100)
, #contactname varchar(100)
, #address varchar(300)
, #email varchar(100)
, #captain varchar(100)
, #requirements varchar(8000)
) as
begin;
if #id = -1
begin;
insert into TeamDetails(TeamName, Phone, ContactName, Address, Email, captain)
values (#txtName, #phone, #contactname, #address, #email, #captain);
set #id = scope_identity();
end;
else
begin;
update TeamDetails
set TeamName = #txtName, Phone = #phone,
ContactName = #contactname,
Address = #address, Email = #email
where TeamId = #id;
end;
exec dbo.TeamRequirements_Merge #id, #requirements;
end;
go
splitting strings reference:
Tally OH! An Improved SQL 8K “CSV Splitter” Function - Jeff Moden
Splitting Strings : A Follow-Up - Aaron Bertrand
Split strings the right way – or the next best way - Aaron Bertrand
string_split() in SQL Server 2016 : Follow-Up #1 - Aaron Bertrand
Ordinal workaround for **string_split()** - Solomon Rutzky
merge reference:
Use Caution with SQL Server''s MERGE Statement - Aaron Bertrand
UPSERT Race Condition With Merge - Dan Guzman
An Interesting MERGE Bug - Paul White
Can I optimize this merge statement - Aaron Bertrand
If you are using indexed views and MERGE, please read this! - Aaron Bertrand
The Case of the Blocking Merge Statement (LCK_M_RS_U locks) - Kendra Little
Writing t-sql merge statements the right way - David Stein
Again, it would be better to use table valued parameters for this:
Table Valued Parameters reference:
Table-Valued Parameters - msdn
User-Defined Table Types - msdn
SQL Server 2008 Table-Valued Parameters and C# Custom Iterators: A Match Made In Heaven! - Leonard Lobel
Table Value Parameter Use With C# - Jignesh Trivedi
Using Table-Valued Parameters in SQL Server and .NET - Erland Sommarskog
Maximizing Performance with Table-Valued Parameters - Dan Guzman
Maximizing throughput with tvp - sqlcat
How to use TVPs with Entity Framework 4.1 and CodeFirst
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
Is it possible to send a list of IDs to a stored procedure from c#?
UPDATE Germs
SET Mutated = ~Mutated
WHERE (GermID IN (ids))
This may be a dirty hack, but you can create a temp table and then join to it from within your stored procedure (assuming they are accessed during the same connection). For example:
CREATE TABLE #ids (id int)
INSERT INTO #ids VALUES ('123') -- your C# code would generate all of the inserts
-- From within your stored procedure...
UPDATE g
SET Mutated = ~Mutated
FROM Germs g
JOIN #ids i ON g.GermID = i.id
You could try what i have made do with:-
Create a function called Split_String
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
CREATE FUNCTION [dbo].[Split_String]
(
#MyString varchar(5000)
)
RETURNS #Results TABLE
(
Value varchar(1000)
)
AS
BEGIN
DECLARE #Pos int
DECLARE #StrLen int
DECLARE #MyLen int
DECLARE #MyVal varchar
SET #pos = 1
SET #MyLen = 1
WHILE #MyString <> ''
BEGIN
SET #MyLen = charindex(',',#MyString)
IF #MyLen = 0 SET #MyLen = Len(#MyString)
INSERT #Results SELECT replace(substring(#MyString, #pos, #MyLen),',','')
SET #MyString = SUBSTRING(#MyString,#MyLen+1,len(#MyString))
END
RETURN
END
Then when you use IN() use in the following fashion with a comma separated string:-
SELECT * FROM [youDataBase].[dbo].[Split_String] (<#MyString, varchar(5000),>)
According to This article, you could try the Table Value Parameter.
Yep, you can use a chunk of XML to build your list of ID's. Then you can use OPENXML and select from that record set.
Look up OPENXML, sp_preparexmldocument, sp_removexmldocument