tsql trigger for copy older data before update - tsql

i need help to create a trigger, i have a database with this table: test01(id, name, id_parent)
CREATE TABLE [dbo].[test01](
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](64) NOT NULL,
CONSTRAINT [PK_test01] PRIMARY KEY CLUSTERED
(
[id] ASC
)
when an update is executed i need to copy the update row in the same table.
Example data before update
id, name, id_parent
1 , 'bob', null
2 , 'jak', null
if i send:
update test01 set name='newbob' where id=1
i need this result
id, name, id_parent
1 , 'newbob', null <---- updated row
2 , 'jak', null
3 , 'bob', 1 <---- copy of previous row with id_parent referenced to the updated row
i need help to create a trigger for this.
my non working version:
CREATE TRIGGER testtrg
ON test01
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
insert into test01
select * from inserted
END
GO

it works. you needed to map the id into the id_parent column
drop table test01
CREATE TABLE [dbo].[test01](
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](64) NOT NULL,
[id_parent][int] NULL,
CONSTRAINT [PK_test01] PRIMARY KEY CLUSTERED
(
[id] ASC
));
insert into test01 (name,id_parent)
values('bob', null),('jak', null)
select * from test01
CREATE TRIGGER testtrg
ON test01
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON;
insert into test01(name,id_parent)
select name,id from inserted
END
update test01 set name='bob2' where id=1
select * from test01
output:
id name id_parent
1 bob NULL
2 jak NULL
3 bob2 1

Related

Why doesn't the deleted table in a FOR/AFTER DELETE Trigger contain data of the Deleted Record?

Given the following audit table:
CREATE TABLE Auditing.[Record Deletion Times]
(
ID BIGINT IDENTITY NOT NULL,
[Schema] NVARCHAR(128) NOT NULL,
[Table] NVARCHAR(256) NOT NULL,
[Record ID] INT NOT NULL,
[Date-Time] DATETIME2 NOT NULL,
[Record Information] NVARCHAR(1024) NULL,
CONSTRAINT [Record Deleted Times Primary Key] PRIMARY KEY CLUSTERED
(
ID ASC
),
CONSTRAINT [Record Deleted Modified Times Unique Key] UNIQUE NONCLUSTERED
(
[Schema] ASC,
[Table] ASC,
[Record ID] ASC,
[Date-Time] ASC
)
)
and the following data table:
CREATE TABLE [dbo].[Items]
(
[ID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Key] [varchar](50) NOT NULL,
[Value] [varchar](255) NOT NULL
)
I want a trigger that will record information to Record Deletion Times when it is deleted from Items. I have found that I am able to do this with an INSTEAD OF trigger (whereby I record the data then manually delete the record in the trigger) but was wondering why a FOR or AFTER trigger does not do the same thing without the need for me performing the deletion myself. My guess is that deleted doesn't contain any data about the record that was deleted once it was deleted (what's the best way to debug a trigger?).
This is the trigger I hoped to use which failed to record anything in Record Deletion Times:
CREATE TRIGGER [Items Deleted]
ON Items
FOR DELETE
AS
INSERT INTO Auditing.[Record Deletion Times]
SELECT
'dbo',
'Items',
deleted.ID,
GETUTCDATE(),
CONCAT
(
'Key: ''',
Items.Key,
''' Value: ''',
Items.Value,
''''
)
FROM Items
JOIN deleted ON deleted.ID = Items.ID
This is the trigger I ended-up using instead:
CREATE TRIGGER [Items Deleted]
ON Items
INSTEAD OF DELETE
AS
BEGIN
INSERT INTO Auditing.[Record Deletion Times]
SELECT
'dbo',
'Items',
deleted.ID,
GETUTCDATE(),
CONCAT
(
'Key: ''',
Items.Key,
''' Value: ''',
Items.Value,
''''
)
FROM Items
JOIN deleted ON deleted.ID = Items.ID
DELETE Items
FROM Items
JOIN deleted ON deleted.ID = Items.ID
END
You should not be selecting from your Items table since the row(s) you want are now deleted.
Just select from Deleted
Ie
INSERT INTO RecordDeletionTimes
SELECT
'dbo',
'Items',
ID,
GETUTCDATE(),
CONCAT
(
'Key: ''',
[Key],
''' Value: ''',
Value,
''''
)
FROM deleted ;
See Demo Fiddle
The best way to debug your trigger is to just select * from deleted and test in SSMS using a begin tran/rollback.

PostgreSQL trigger for inserting an entry in table2 AFTER a row is inserted in table1 (using the values from newly inserted row in table1)

I have displayed my database schema below.
CREATE TABLE table_group
(
group_id serial NOT NULL,
group_creator_id integer NOT NULL,
group_name character varying(20) NOT NULL,
active_status boolean NOT NULL,
PRIMARY KEY (group_id),
)
CREATE TABLE table_group_members
(
group_member_id serial NOT NULL,
group_id integer REFERENCES table_group (group_id) NOT NULL,
member_user_id integer REFERENCES table_group (group_creator_id) NOT NULL,
PRIMARY KEY (group_member_id)
)
I want to INSERT a new row in the table table_group_members as soon a new row is inserted in table table_group.
I want to pass the group_id and group_creator_id of the newly inserted row in the table table_group as parameters to INSERT query for the table table_group_members
How should I do it using the PostgreSQL TRIGGER?

How can i create auto increment column to my existing column?

I am working with Oracle 12c in which I have below table structure:-
CREATE TABLE patients (
patient_id Integer NOT NULL,
customer_id Integer NOT NULL,
title varchar(5) NOT NULL,
fname varchar(125) NOT NULL,
lname varchar(125) NOT NULL,
dob date NOT NULL,
is_medical_card NUMBER(1) NOT NULL CHECK (is_medical_card IN (0,1)),
scheme_number Integer NOT NULL,
status varchar(50) NOT NULL,
created_on date NOT NULL,
last_update_date date NOT NULL,
consent_flag NUMBER(1) NOT NULL CHECK (consent_flag IN (0,1)),
relationship varchar(50) NOT NULL
);
Where patient_id is my primary key so now I want to make it auto increment as well so please let me how can I do this so make it auto increment.
Thanks!
Need to create auto increment to existing column.
You might want to use Identities - Creating a table with an Identity gives you the chance to omit the ID values and let Oracle use a sequence on your desired column:
1. Let's Create the Table:
CREATE TABLE identities (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
description varchar2(100) NOT NULL
);
Table created.
2. You'll want to create a primary key to ensure uniqueness:
alter table identities add constraint id_pk primary key (ID);
Table altered.
3. Let's insert some data in different ways:
INSERT INTO identities (description)
VALUES('Insert Description omitting ID');
1 row created.
INSERT INTO identities (id,description)
VALUES(NULL,'Insert with explicit NULL value');
1 row created.
4. Save the work done
commit;
Commit complete.
5. Check the results
select * from identities;
ID DESCRIPTION
---------- ---------------------------------------------
1 Insert Description omitting ID
2 Insert with explicit NULL value
As you can see we dind't specify any number for the ID, but the Identity on the ID column did for us
Note: Mind that you can manually insert an ID, but this will mess up with the Identity as it'll normally do with a standard Sequence:
INSERT INTO identities (id,description)
VALUES(3,'Manually insert an ID value');
1 row created.
INSERT INTO identities (description)
VALUES('Test Nextval');
INSERT INTO identities (description)
*
ERROR at line 1:
ORA-00001: unique constraint (XXX.ID_PK) violated
This error, because it tries to insert a '3' into the ID that was manually inserted with the statement before.
Check the table:
select * from identities;
ID DESCRIPTION
---------- ---------------------------------------------
1 Insert Description omitting ID
2 Insert with explicit NULL value
3 Manually insert an ID value
Re-Run the "NEXTVAL" insert:
INSERT INTO identities (description)
VALUES('Test Nextval');
1 row created.
Re-Check the table:
select * from identities;
ID DESCRIPTION
---------- ---------------------------------------------
1 Insert Description omitting ID
2 Insert with explicit NULL value
3 Manually insert an ID value
4 Test Nextval
Hope this Helps.

Populating Records From 1 table into 2 tables and retreiving ID to be used

I have records from a SOURCE1 table and I need to move those records into 2 different tables called DESTINATION1 and DESTINATION2
I know how to copy records from the SOURCE1 table into the DESTINATION1 table by using a INSERT INTO SELECT statement, but I run into a problem. What I need is when copying the REMARKS data from SOURCE1, I need to copy that into the DESTINATION2 table, retrieve the REFID and copy that REFID into the respective record in my DESTINATION1 table in the column FK_DESTINATION2_REFID.
The criteria is to copy only the records in the SOURCE1 table with the STATUS of 1 and only copy the respective REMARKS data into the DESTINATION2 table if its not null. Also, is it possible to do this without a Stored Procedure, if not, not a big deal.
CREATE TABLE #Source1 (
RefID int IDENTITY(1,1) NOT NULL,
Status bit NULL,
ProviderID int NULL,
Remarks varchar(max) NULL
)
Create Table #Destination1 (
RefID int IDENTITY(1,1) NOT NULL,
Status bit NULL,
ProviderID int NULL,
FK_Destination2_RefID int
)
Create Table #Destination2 (
RefID int IDENTITY(1,1) NOT NULL,
Remarks varchar(max) NULL
)
-- Insert Records into #Source1
Insert Into #Source1 values (1,100,'Test 555')
Insert Into #Source1 values (0,400,'Test 123')
Insert Into #Source1 values (1,300,NULL)
Insert Into #Source1 values (1,500,'Test 999')
Insert Into #Source1 values (1,200,NULL)
--Drop table #Source1
--Drop table #Destination1
--Drop table #Destination2
Results would look like this:
Source1 Table
RefID Status ProviderID Remarks
----------- ------ ----------- -----------
1 1 100 Test 555
2 0 400 Test 123
3 1 300 NULL
4 1 500 Test 999
5 1 200 NULL
Destination1 Table
RefID Status ProviderID FK_Destination2_RefID
----------- ------ ----------- ---------------------
1 1 100 1
2 1 300 NULL
3 1 500 2
4 1 200 NULL
Destination2 Table
RefID Remarks
------ ---------
1 Test 555
2 Test 999
EDIT: My #SOURCE1 table will be hold a dynamic set amount of records. In this instance I have 5 Records. But next time, it could be 50 records. At each time using the #SOURCE1 table, I will truncate the table each time and the REFID will start back to 1. Since this is a temporary holding table for a batch of records, I need to move them permanently to the 2 Destination tables as indicated when finished so in essence they can look like the #SOURCE1 table originally.
Well, you are using IDENTITY property on the #Destination tables. This means you are trying to assign a new PK to them, and it would thus remove the uniqueness / PK --> FK link to the #Source table... and it's unnecessary since your source table is already handling this. So, just remove this property from m the #Destination tables and do your inserts as you suspect. You can still add a UNIQUE CONSTRAINT on the destination tables if you want... but if this is all it is used for you should never run into non-uniqueness. Your FK will not be sequential, but that's because you are restricting what data to insert into it. If you want another PK IDENTITY column, just keep that separate. I have included that below as an example
CREATE TABLE #Source1 (
RefID int IDENTITY(1,1) NOT NULL,
Status bit NULL,
ProviderID int NULL,
Remarks varchar(max) NULL
)
Create Table #Destination1 (
SomePK int IDENTITY(1,1),
RefID int ,
Status bit NULL,
ProviderID int NULL,
FK_Destination2_RefID int
)
Create Table #Destination2 (
SomePK int IDENTITY(1,1),
RefID int ,
Remarks varchar(max) NULL
)
-- Insert Records into #Source1
Insert Into #Source1 values (1,100,'Test 555')
Insert Into #Source1 values (0,400,'Test 123')
Insert Into #Source1 values (1,300,NULL)
Insert Into #Source1 values (1,500,'Test 999')
Insert Into #Source1 values (1,200,NULL)
insert into #Destination2
select
RefID
,Remarks
from #Source1
where
Remarks is not null and Status = 1
insert into #Destination1
select
s.RefID
,s.Status
,s.ProviderID
,d.RefID
from
#Source1 s
left join #Destination2 d on d.RefID = s.RefID
where
s.Status = 1
select * from #Source1
select * from #Destination1
select * from #Destination2
Drop table #Source1
Drop table #Destination1
Drop table #Destination2

Change database dynamically in SQL Server using a stored procedure

I have a question about SQL Server: how to change database name dynamically and use one select and insert statment to load data using a stored procedure.
How to change the database name with insert and select statement while table data loading into another table?
Here each database name related table load into with in the database name related target table.
i.e database: test and source table: emp target table is :emptarget here emp table records load into emptarget similar to another databases
Database names information maintain one table.
USE [test]
GO
CREATE TABLE [dbo].[databaseinformation]
(
[id] [int] NULL,
[databasename] [varchar](50) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[databaseinformation] ([id], [databasename])
VALUES (1, N'test'), (2, N'test1')
GO
Table1 : source : emp and datbasename: test
USE [test]
CREATE TABLE [dbo].[emp]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
INSERT [dbo].[emp] ([id], [name], [sal])
VALUES (19, N'hd', 40), (1, N'g', 10),
(9, N'dk', 90), (80, N'dhe', 80)
GO
Target table : emptarget and databasename: test
USE [test]
CREATE TABLE [dbo].[emptarget]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
----table 2: emp and databasename: test1
USE [test]
CREATE TABLE [dbo].[emp]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
INSERT [dbo].[emp] ([id], [name], [sal])
VALUES (50, N'kl', 80), 39, N'abc', 10)
go
Target table : emptarget and databasename: test1
USE [test1]
CREATE TABLE [dbo].[emptarget]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
Finally need to load data like below
Database: test and table : emptarget
id |name |sal
19 |hd |40
1 |g |10
9 |dk |90
80 |dhe |80
Database: test1 and table : emptarget
id |name |sal
50 |kl |80
39 |abc |10
I tried like below
USE [test]
GO
insert into emptarget
select * from emp
USE [test1]
GO
insert into emptarget
select * from emp
Here I do not want run two queries separately. I need to run querying using single select and insert statement to load data correspong tables with databases.
Please tell me how to write query to achive this task in SQL Server
Actually I have no idea about why you don't do this.
insert into test.emptarget select * from test.emp;
insert into test1.emptarget select * from test1.emp;
So I think you just want one query to do this.
create procedure emptoemptarget (#DBName nvarchar(10))
as
begin
declare #sql nvarchar(1000)
set #sql = 'insert into ' + #DBName + '.emptarget select * from ' + #DBName + '.emp'
exec (#sql)
end
select dbo.emptoemptarget(name) from sys.databases where name in ('test','test1')