I have two exactly same tables. My question: is there any way when i'm inserting something in first table automatically sql server to copy this row into another table.
I know that i can do it manually
select * into table1 from table2 where table2ID=#table2ID
But i'm wondering if i can create a table dynamically and set it when a row is inserted, copy row's data into another table also.
So with this way i dont need to run extra code to do that, sql will do this automatically
You can use a TRIGGER which is an object that you link to a table with a particular operation (INSERT, UPDATE, DELETE or any combination of those). The trigger's code will execute on each operation done to the linked table.
Basic example:
CREATE TRIGGER dbo.CopyToTable2 ON Table1
AFTER INSERT -- The trigger will execute after any insert done to Table1
AS
BEGIN
SET NOCOUNT ON
INSERT INTO Table2 (
Column1,
-- OtherColumns
)
SELECT
I.Column1
-- OtherColumns
FROM
inserted AS I -- "inserted" is a special table that references the trigger's tracking table for new or updated records
END
The use of a trigger is appropriate here. It might look something like this:
CREATE TRIGGER SomeTriggerName ON theSourceTable
FOR INSERT
AS
INSERT INTO DestinationTable
(column1, someothercolumn)
SELECT (column1, someothercolumn)
FROM inserted
Related
In my SQl Server I have a table of around 40 attributes/columns. There is a daily load which might update any of these columns. I want to capture the changes in these columns in a separate table with a reason code column telling which column value changed. There might be instances where more than one column value might get changed in a single daily load, in that case the changed log table should capture all these changes separately in rows with each row depicting the individual change.
For Example:
TableA(column1(pk),column2,column3,column4)
values(1,100,ABC,999)
After update:
TableA(column1(pk),column2,column3,column4)
values(1,100,ACD,901)
The corresponding change log table should have two entries:
TabChangeLog(column1,before,after,reason);
values(1,ABC,ACD,'column3 changed')
values(1,999,901,'column4 changed')
I tried implementing this through triggers but am not able to figure out a way to separate each of these changes in separate rows when there are more than one changes. Please help
You need to create a trigger like :
create trigger trigger_name
instead of update as
if update(column1)
begin
insert into TabChangeLog
select inserted.column1, inserted.column3, deleted.column3, 'column3', 'update/change'
from inserted i inner join deleted d
on i.column1 = d.column2
end
if update(column2)
begin
insert into TabChangeLog
select inserted.column1, inserted.column2, deleted.column2, 'column2', 'update/change'
from inserted i inner join deleted d
on i.column1 = d.column2
end
...
https://www.tutorialgateway.org/instead-of-update-triggers-in-sql-server/
Microsoft SQL Server 2016 has a thing called Temporal Tables which would probably simplify your job a lot. It lets you rewind a dataset through time to see the changes:
https://learn.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables?view=sql-server-2017
If you don't want to go that route and use triggers instead. UPDATE triggers have two tables inserted and deleted that let you know what the row state was before and after.
*Edit: These are tables so you have to use SELECT INTO etc to interact with them you can't do conditional logic (if /else)
CREATE TABLE [dbo].[Table1](
[Id] [int] NOT NULL,
[Tail] [int] NOT NULL,
CONSTRAINT [PK_Table1_1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
)
CREATE TABLE Table1_Audit
(
Audit varchar(100)
)
--drop trigger Table1_OnUPDATE
CREATE TRIGGER Table1_OnUPDATE
ON dbo.Table1
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
INSERT INTO Table1_Audit ([Audit])
select CONCAT('Tail changed to' ,inserted.Tail,' for pk Id=',inserted.Id) from inserted inner join
deleted on inserted.Id = deleted.Id --pk must be the same
where
inserted.Tail <> deleted.Tail --field x must be different
END
GO
--truncate table Table1_Audit
--update Table1 set Tail = 5
select * from Table1_Audit
I am loading data from a JSON file to a table "main.jsontable" the trigger job is to insert the data of all different countries from "main.jsontable" into "main.country" table. My problem is that the trigger needs to handle inserting multiple rows my current code is:
create or alter trigger main.afterParsing
on main.jsontable
after insert
as
begin
declare #country nvarchar(50);
insert into main.country(countryName)
values(#country)
end;
but I get this error (obviously because triggers can only handle inserting 1 row at a time):
Cannot insert the value NULL into column 'countryName', table 'assignment2.main.country'; column does not allow nulls. INSERT fails.
Does anyone know how I can use the trigger to insert multiple rows?
Thanks
You need to use the Inserted pseudo table, and you need to understand that it can contain multiple rows (if your INSERT statement inserted more than 1 row at once), and you need to treat that table accordingly, using a proper set-based approach.
Try something like this:
create or alter trigger main.afterParsing
on main.jsontable
after insert
as
begin
insert into main.country(countryName)
select countryName
from Inserted
-- if the data being inserted could have NULL in the
-- countryName - filter those entries out
where countryName is not null
end;
If I execute a procedure that drops a table and then recreate it using 'SELECT INTO'.
IF that procedure raises an exception after dropping the table, does table dropping take place or not?
Unless you wrap them in a transaction,table will be dropped since each statement will be considered as an implicit transaction..
below are some tests
create table t1
(
id int not null primary key
)
drop table t11
insert into t1
select 1 union all select 1
table t11 will be dropped,even though insert will raise an exception..
one more example..
drop table orderstest
print 'dropped table'
waitfor delay '00:00:05'
select * into orderstest
from Orders
now after 2 seconds,kill session and you can still see orderstest being dropped
I checked with some other statements other than select into ,i don't see a reason why select into will behave differently and this applies even if you wrap statements in a stored proc..
IF you want to rollback all,use a transaction or more better use set xact_Abort on
Yes, the dropped table will be gone. I have had this issue when I script a new primary key. Depending on the table, it saves all the data to a table variable in memory, drops the table, creates a new one with the new pk, then loads the data. If the data violates the new pk, the statement fails and the table variable is dropped leaving me with a new table and no data.
My practice is to create the new table with a slightly different name, load the data, change both table names in a statement, then once all the data is confirmed loaded, drop the original table.
I m making a mistake somewhere but can't figure out.
Scenario is this:
Whenever a new row is inserted in table 'TestTrigger', the table TriggerInsert should get a value capturing time when a new row was inserted in TestTrigger.
The problem is, whenever the trigger hits, instead of just a new row, the whole table gets repopulated in TestTrigger, each time. I only want to capture, the new rows not the entire table getting inserted on each trigger.
Here is my trigger:
USE [irfaan]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Trigger [dbo].[InsertTriggerTest] on [irfaan].[dbo].[TestTrigger]
--For Insert
After insert
as
INSERT into TriggerInsert (CurrTime, IOFNum) SELECT (GetDate()), SONum FROM TestTrigger
Please assist where I am going wrong.
If you want to look at just the rows that were inserted, you must use the Inserted pseudo table - not the dbo.TestTrigger base table....
ALTER TRIGGER dbo.InsertTriggerTest
ON irfaan.dbo.TestTrigger
FOR INSERT
AS
INSERT INTO TriggerInsert (CurrTime, IOFNum)
SELECT GETDATE(), SONum
FROM Inserted
Your SELECT query is returning all rows from your source table (TestTrigger). Use the table inserted instead. It will contain just the rows that are being inserted into TestTrigger instead of all of the rows as you are currently getting.
INSERT into TriggerInsert (CurrTime, IOFNum) SELECT (GetDate()), SONum FROM Inserted
High level I have two tables that need to have some of the data mirrored. I can't go through and change all of the code to write to both so I thought I'd use a SQL trigger to insert data into the 2nd table anytime data is inserted into the 1st. Here is where I am stuck:
CREATE TRIGGER new_trigger_INSERT
ON old_table
FOR INSERT
INSERT INTO new_table (id, first_name, last_name)
VALUES () --This is where I'm lost, I need to insert some of the data from the insert that executed this trigger
Any help is appreciated, also if there is a better way to accomplish this let me know.
Use the 'inserted' table:
CREATE TRIGGER new_trigger_INSERT
ON old_table
FOR INSERT
INSERT INTO new_table (id, first_name, last_name)
SELECT col1, col2, col3 FROM inserted
[PS: Don't forget to ensure your triggers handle multiple rows...]
Ref. Create Trigger
Good article: Exploring SQL Server Triggers
In the triggers you have "inserted" and "deleted" tables. In this case you only use the "inserted" table, but in update trigger you use both.