I want to create a table implementing partition function such that if the number of records becomes 5+1 then the first recor gets deleted For example if the records are 1,2,3,4,5 and we insert 6th record then 1st record gets deleted and remaining records are 2,3,4,5,6
After your Insert you could add something like:
delete from mytable
where RecordID <= select(MAX(RecordID)-5 from mytable);
So that everything before the 5 most recent rows are deleted.
You could use a trigger after insert to delete the surplus rows. Try this example:
BEGIN TRANSACTION;
SET NOCOUNT ON;
create table t (id int identity(1,1), val char(1))
go
create trigger limit_t on t for insert as
begin
if (select count(*) from t) > 5
delete from t where id <= (select max(id)-5 from t);
end
go
-- insert five rows
insert t (val) values ('a'),('b'),('c'),('d'),('e')
-- insert a sixth and seventh row
insert t (val) values ('f'),('g')
-- retrieve content after last insert
select * from t
-- the table now holds values [c,d,e,f,g]
ROLLBACK TRANSACTION;
Related
I have a table table1 with some data:
create table table1
(
c1 varchar(20),
c2 varchar(20)
)
insert into table1 values('1','A')
insert into table1 values('2','B')
insert into table1 values('3','C')
insert into table1 values('4','D')
insert into table1 values('5','E')
insert into table1 values('6','F')
Now I created another table with the same structure called table2 :
create table table2
(
c1 varchar(20),
c2 varchar(20)
)
Then I created an After Insert trigger on table2 :
CREATE TRIGGER trgAfterInsert
ON [dbo].[table2]
FOR INSERT
AS
declare #c1 varchar(20);
declare #c2 varchar(20);
declare #audit_action varchar(100);
select #c1 = i.c1 from inserted i;
select #c2 = i.c2 from inserted i;
set #audit_action = 'Inserted Record -- After Insert Trigger.';
insert into table2_Audit(c1, c2, Audit_Action, Audit_Timestamp)
values(#c1, #c2, #audit_action, getdate());
PRINT 'AFTER INSERT trigger fired.'
GO
There is a problem that when i copy all data of table1 to tabe2 then in Audit table only one record show.It not show all inserted record.
I use this query for copy the record in table2:-
insert into table2(c1,c2) select c1,c2 from table1
Your trigger fires once for each insert statement issued against this table. not one for each row inserted in the table. Hence if more than one row is inserted you trigger definition should be able to handle more than one row.
Instead of using variables to capture values from inserted table and then insert them in table two, simply select from the inserted table and insert the data into Table2_audit.
A trigger to handle this would look something like........
CREATE TRIGGER trgAfterInsert ON [dbo].[table2]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
insert into table2_Audit (c1,c2,Audit_Action,Audit_Timestamp)
SELECT C1
, C2
, 'Inserted Record -- After Insert Trigger.'
, GETDATE()
FROM inserted ;
PRINT 'AFTER INSERT trigger fired.'
END
GO
Trigger is fired once per entire operation, change your code to:
CREATE TRIGGER trgAfterInsert ON [dbo].[table2]
FOR INSERT
AS
BEGIN
DECLARE #audit_action VARCHAR(100) = 'Inserted Record -- After Insert Trigger.';
INSERT INTO table2_Audit(c1,c2,Audit_Action,Audit_Timestamp)
SELECT i.c1, i.c2, #audit_action, GETDATE()
FROM inserted i;
END
Second don't use PRINT inside trigger;
More info
The behavior you are seeing is by design. DML triggers in SQL Server
are statement level triggers - they are fired once after
INSERT/UPDATE/DELETE/MERGE irrespective of how many rows are affected
by the DML statement. So you should write your logic in the trigger to
handle multiple rows in the inserted/deleted tables
I am trying to insert into 3 tables from one single select statement. Here is what I am trying to do:
insert into dbo.temp1 (name, location, city)
select name, location, city from mytable.
I want to be able to insert into 3 tables once I run the select statement like inserting into temp1, temp2 and temp3.
How can I do this? Thanks.
You can do it maximum for 2 tables with using output:
insert into dbo.temp1 (name, location, city)
output inserted.name, inserted.location, inserted.city into temp2
select name, location, city from mytable
You can't do this in one step*
What you can do is to insert the initial query into a #temp table (or a #table variable) as a staging area, and then insert into the tables from there. Wrap the steps in a transaction to retain ACID:
BEGIN TRAN
select name, location, city
into #TEMP
from mytable;
insert into temp1(name, location, city)
select name, location, city
from #TEMP;
-- Same for temp2 and temp3.
COMMIT TRAN
* Excluding hacks such as a view with an Instead-of Trigger.
The staging table is important from a concurrency point of view, as repeating the original query 3 times may result in different results if there are interim concurrent changes to the source table.
You can.
With a trick.
Create a view, then create an 'instead of' trigger for insert on that view where you insert the stuff into your tables. If you now insert into your view, you finally insert data in 3 tables. Here's a demo
-- 1. create 3 test tables
create table t1( id int, f1 varchar(20))
create table t2( id int, f2 varchar(20))
create table t3( id int, f3 varchar(20))
go
-- 2. create the view
create view Tt as
select t1.ID, t1.f1, t2.f2,t3.f3
from t1
join t2 on t1.ID=t2.ID
join t3 on t1.ID=t3.id
go
-- 3. create the trigger
create trigger Tr_Test on Tt INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
insert into t1 select id,f1 from inserted
insert into t2 select id,f2 from inserted
insert into t3 select id,f3 from inserted
END
GO
-- 4. now do your insert with a single select
insert into tt
select 1,'A','B','C'
-- 5. and watch the 3 tables
select * from t1
select * from t2
select * from t3
voilá, one insert, 3 tables got modified. Wwe don't count the hidden trigger, do we ;-)
There is no way to insert into X tables with one query (Ok it its with insert and output to table).
So you have to write 3 queries.
Or you can generate SQL statments with dynamic queries.
I don't believe you can insert into multiple tables in one statement. You can definitely do it in one transaction, however.
BEGIN TRANSACTION
INSERT INTO dbo.temp1 (name, location, city)
SELECT name, location, city
FROM myTable
INSERT INTO dbo.temp2 (name, location, city)
SELECT name, location, city
FROM myTable2
COMMIT TRANSACTION
You can insert into multiple tables with one select statement using a TRIGGER.
CREATE TRIGGER TEMP2_TEMP3_INSERT ON TEMP1
AFTER INSERT AS
BEGIN
/* create your insert statements for TEMP2 and TEMP3 here
referencing the data from the first insert */
END;
GO
MySQL doesn't support multi-table insertion in a single INSERT statement. Oracle is the only one I'm aware of that does, oddly...
However, you CAN use a transaction and have both of them be contained within one transaction.
MySQL:
START TRANSACTION;
INSERT INTO table1 VALUES ('1','2','3');
INSERT INTO table2 VALUES ('1','2','3');
COMMIT;
SQL Server:
BEGIN TRAN;
INSERT INTO table1 VALUES ('1','2','3');
INSERT INTO table2 VALUES ('1','2','3');
COMMIT;
SQL Server with error catching/rollback:
BEGIN TRANSACTION [Tran1]
BEGIN TRY
INSERT INTO table1 VALUES ('1','2','3')
INSERT INTO table2 VALUES ('1','2','3')
COMMIT TRANSACTION [Tran1]
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION [Tran1]
END CATCH
GO
The issue I am having is when I insert more than one value into a table or delete a value that exists more than once in a table. I am unsure how to work around this issue.
`CREATE TRIGGER [dbo].[Q5Trigger]
ON [dbo].[WF]
AFTER INSERT, DELETE
AS
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'AuditTable')
BEGIN
CREATE TABLE [dbo].[AuditTable](
Word VARCHAR(100),
Frequency INT,
Date DATETIME,
Type VARCHAR(100)
)
END
IF EXISTS (SELECT * FROM inserted)
BEGIN
INSERT INTO AuditTable VALUES((SELECT Word FROM inserted),(SELECT Frequency FROM inserted), CURRENT_TIMESTAMP, 'Inserted')
END
IF EXISTS (SELECT * FROM deleted)
BEGIN
INSERT INTO AuditTable VALUES((SELECT Word FROM deleted),(SELECT Frequency FROM deleted), CURRENT_TIMESTAMP, 'Deleted')
END`
You misunderstand how triggers and INSERTED and DELETED work. When you insert 50 records into a table with a trigger, the trigger gets called once and the INSERTED table has 50 records in it. To do what you are doing, you must insert into the 1 table ALL the records of the other table.
INSERT INTO AuditTable (Word,Frequency,LogWhen,LogType)
SELECT Word,Frequency, CURRENT_TIMESTAMP, 'Inserted' FROM inserted
Your delete would be very similar to this.
Can anyone point out why this insert trigger is not inserting the new rows into the IVRTestB table?
If Object_ID('MyTrig3', 'TR') IS Not Null
Drop Trigger MyTrig3;
GO
Alter Trigger MyTrig3
On dbo.IVRTest
After Insert, update
AS
Begin
SET NOCOUNT ON;
Insert Into [dbo].[IVRTestB]
(IVRAID, IVRName, DayNumber, OpenFlag)
Select
'i.IVRAID', 'i.IVRName', 'i.DayNumber', 'i.OpenFlag'
From inserted i
INNER JOIN dbo.IVRTestB b
On i.IVRAID = b.IVRAID
END
By putting every column of Inserted into single quotes, you're effectively inserting string literals into your destination table - not the column values!
Use this code instead:
INSERT INTO [dbo].[IVRTestB] (IVRAID, IVRName, DayNumber, OpenFlag)
SELECT
i.IVRAID, i.IVRName, i.DayNumber, i.OpenFlag -- *NO* single quotes here!!!!
FROM
inserted i
-- change this WHERE clause to insert those rows that AREN'T alredy in IVRTestB !
WHERE
i.IVRAID NOT IN (SELECT DISTINCT IVRAID FROM dbo.IVRTestB)
Alter Trigger MyTrig3
On dbo.IVRTest
After Insert
AS
Begin
SET NOCOUNT ON;
IF EXISTS ( SELECT
1
FROM
INSERTED
WHERE
INSERTED.DayNumber IS NULL )
Insert Into
[dbo].[IVRTestB]
(IVRAID,
IVRName,
DayNumber,
OpenFlag)
Select
i.IVRAID,
i.IVRName,
i.DayNumber,
i.OpenFlag
From inserted i
WHERE
INSERTED.DayNumber IS NULL
END
Mohan,
You change nearly worked, I just had to change the not nulls to is not null and the alias for inserted to I
Alter Trigger MyTrig3
On dbo.IVRTest
After Insert
AS
Begin
SET NOCOUNT ON;
IF EXISTS ( SELECT
1
FROM
INSERTED
WHERE
INSERTED.DayNumber IS NOT NULL )
Insert Into
[dbo].[IVRTestB]
(IVRAID,
IVRName,
DayNumber,
OpenFlag)
Select
i.IVRAID,
i.IVRName,
i.DayNumber,
i.OpenFlag
From inserted i
WHERE
i.DayNumber IS NOT NULL
END
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'myTrigger' AND type = 'TR')
BEGIN
DROP TRIGGER myTrigger
END
GO
go
create trigger myTrigger
on mytable_backup
instead of insert
as
begin
declare #seq int
select #seq = seq from inserted
if exists (select * from mytable_backup where seq= #seq) begin
delete from mytable_backup where seq=#seq
end
insert into mytable_backup
select * from inserted
end
go
I've written this trigger to check while inserting if seq column is repeated then update the previous row with same seq if seq doesn't exits insert it with new seq.
In ssis package I'm using OLEDB table(Mytable) as a source which contains.
Name,Age,Seq
Gauraw,30,1
Gauraw,31,1
Kiran,28,3
Kiran,29,3
kiran,28,3
Venkatesh,,4
Venkatesh,28,4
Now I'm loading this table to OLEDB destination(Mytable_backup) as destination.
I suppose to get output as.
Gauraw,31,1
kiran,28,3
Venkatesh,28,4
But I'm getting all the records from Mytable into Mytable_backup.
is anything wrong with my trigger?
I think that this trigger will just take the first row and compare it with the existing. If I understand what you want to do you can quit easy do this:
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'myTrigger' AND type = 'TR')
BEGIN
DROP TRIGGER myTrigger
END
GO
go
create trigger myTrigger
on mytable_backup
instead of insert
as
begin
insert into mytable_backup
select
*
from
inserted
WHERE NOT EXISTS
(
SELECT
NULL
FROM
mytable_backup AS mytable
WHERE
inserted.seq=mytable.seq
)
end
go
EDIT
So I found out what was going on. If you insert all of the rows in one go the inserted contains all the rows.. Sorry my mistake. If there are duplicates in your data your example do not show which to choose. I have chosen the one with the maximum of age (don't know what your requirements is). Here is a update with the full example
Table structure
CREATE TABLE mytable_backup
(
Name VARCHAR(100),
Age INT,
Seq INT
)
GO
Trigger
create trigger myTrigger
on mytable_backup
instead of insert
as
begin
;WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY inserted.Seq ORDER BY Age) AS RowNbr,
inserted.*
FROM
inserted
WHERE NOT EXISTS
(
SELECT
NULL
FROM
mytable_backup
WHERE
mytable_backup.Seq=inserted.Seq
)
)
insert into mytable_backup(Age,Name,Seq)
SELECT
CTE.Age,
CTE.Name,
cte.Seq
FROM
CTE
WHERE
CTE.RowNbr=1
end
GO
Insert of test data
INSERT INTO mytable_backup
VALUES
('Gauraw',30,1),
('Gauraw',31,1),
('Kiran',28,3),
('Kiran',29,3),
('kiran',28,3),
('Venkatesh',20,4),
('Venkatesh',28,4)
SELECT * FROM mytable_backup
Drop of the database objects
DROP TRIGGER myTrigger
DROP TABLE mytable_backup
Your original code has two flaws:
It assumes that only one record is inserted at a time.
Your insert into mytable_backup happens outside of the if condition. That insert will execute every time.