Update Trigger SQL Server 2008 - sql

I have created a view in SQL server 2008 which consists of the joining of about 5 different tables to access the data i need.
How would i create an update trigger to update a field within this view? So for example if i wanted to update all first names to peter if the last name is smith.
If Fname = peter
update Sname to Smith
end if
Many thanks in advance
UPDATE
this is what i have so far
CREATE TRIGGER SurName
ON ViewCustomer
AFTER UPDATE
AS
if FName= 'Peter'
BEGIN
update ViewCustomer set SName= 'Smith'
SET NOCOUNT ON;
END
GO

This should do the job.
Table and view definitions.
CREATE TABLE Customer
(ID int,
FName varchar(200),
SName varchar(200),
RoleID int);
CREATE TABLE CustomerRole
(RID int,
Name varchar(100));
CREATE VIEW ViewCustomer AS
SELECT *
FROM Customer JOIN CustomerRole on RoleID = RID;
Trigger definition.
CREATE TRIGGER ViewCustomerTrigger ON ViewCustomer
INSTEAD OF UPDATE
AS
BEGIN
SET NOCOUNT ON
UPDATE Customer
SET FName = I.FName,
SName = CASE I.FName WHEN 'Peter' THEN 'Smith' ELSE I.SName END,
RoleID = I.RoleID
FROM INSERTED I JOIN Customer C ON I.ID = C.ID
UPDATE CustomerRole
SET Name = I.Name
FROM INSERTED I JOIN CustomerRole R ON I.RID = R.RID
END
GO
Sample data
INSERT INTO Customer (ID, FName, SName, RoleID)
VALUES (1, 'John', 'Wayne', 1);
INSERT INTO Customer (ID, FName, SName, RoleID)
VALUES (2, 'Jack', 'Jackson', 1);
INSERT INTO CustomerRole (RID, Name)
VALUES (1, 'Manager');
This update will cause the trigger to update the SName to 'Smith'
UPDATE ViewCustomer
SET FName = 'Peter'
WHERE ID = 1
Here is a SQLFiddle for it.

You need to create an INSTEAD OF trigger for views. You can check on:
http://msdn.microsoft.com/en-us/library/ms188601.aspx

Related

Insert into a Informix table or update if exists

I want to add a row to an Informix database table, but when a row exists with the same unique key I want to update the row.
I have found a solution for MySQL here which is as follows but I need it for Informix:
INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE name="A", age=19
You probably should use the MERGE statement.
Given a suitable table:
create table table (id serial not null primary key, name varchar(20) not null, age integer not null);
this SQL works:
MERGE INTO table AS dst
USING (SELECT 1 AS id, 'A' AS name, 19 AS age
FROM sysmaster:'informix'.sysdual
) AS src
ON dst.id = src.id
WHEN NOT MATCHED THEN INSERT (dst.id, dst.name, dst.age)
VALUES (src.id, src.name, src.age)
WHEN MATCHED THEN UPDATE SET dst.name = src.name, dst.age = src.age
Informix has interesting rules allowing the use of keywords as identifiers without needing double quotes (indeed, unless you have DELIMIDENT set in the environment, double quotes are simply an alternative to single quotes around strings).
You can try the same behavior using the MERGE statement:
Example, creation of the target table:
CREATE TABLE target
(
id SERIAL PRIMARY KEY CONSTRAINT pk_tst,
name CHAR(1),
age SMALLINT
);
Create a temporary source table and insert the record you want:
CREATE TEMP TABLE source
(
id INT,
name CHAR(1),
age SMALLINT
) WITH NO LOG;
INSERT INTO source (id, name, age) VALUES (1, 'A', 19);
The MERGE would be:
MERGE INTO target AS t
USING source AS s ON t.id = s.id
WHEN MATCHED THEN
UPDATE
SET t.name = s.name, t.age = s.age
WHEN NOT MATCHED THEN
INSERT (id, name, age)
VALUES (s.id, s.name, s.age);
You'll see that the record was inserted then you can:
UPDATE source
SET age = 20
WHERE id = 1;
And test the MERGE again.
Another way to do it is create a stored procedure, basically you will do the INSERT statement and check the SQL error code, if it's -100 you go for the UPDATE.
Something like:
CREATE PROCEDURE sp_insrt_target(v_id INT, v_name CHAR(1), v_age SMALLINT)
ON EXCEPTION IN (-100)
UPDATE target
SET name = v_name, age = v_age
WHERE id = v_id;
END EXCEPTION
INSERT INTO target VALUES (v_id, v_name, v_age);
END PROCEDURE;

SQL Server: Insert if doesn't exist, else update and insert in another table

I'm inserting new records into a Person table, and if there's already a record with the same SSN, I want to backup this old record to another table (let's call it PersonsBackup) and update the row with my new values. There is an identity column in Person table that serves as my primary key, which has to be the same.
Source table structure:
Name | Addr | SSN
Person table structure:
PrimaryKeyID | Name | Addr | SSN
PersonBackup table structure:
BackupKeyID | Name | Addr | SSN | OriginalPrimaryKeyID
where OriginalPrimaryKeyID = PrimaryKeyID for the record that was backed up. How can this be done? I was thinking of using cursor to check if SSN matches, then insert that record accordingly, but I've been told that using cursors like this is very inefficient. Thanks for your help!
You can do so like this, combine the insert/update using MERGE
INSERT INTO PersonBackup
SELECT P.Name, P.Addr, P.SSN, P.PrimaryKeyID
FROM Person P
INNER JOIN source s ON P.SSD = s.SSD
MERGE Person AS target
USING (SELECT Name, Addr, SSN FROM SOURCE) AS source (NAME, Addr, SSN)
ON (target.SSN = source.SSN)
WHEN MATCHED THEN
UPDATE SET name = source.name, Addr = source.Addr
WHEN NOT MATCHED THEN
INSERT(Name, Addr, SSN)
VALUES(source.name, source.addr, source.SSN)
Here is some pseudocode to get you started:
Insert into PersonBackup table all Person data where SSN joins to Source data
Insert into Person table all Source data where SSN doesn't join to Person data
Update Person table all Source data where SSN joins to Person Data
So some hints:
Figure out a query that returns Person data where SSN is in the Source data.
Figure out a query that returns Source Data where SSN isn't in Person data.
Check out the syntax for INSERT INTO.
Check out the syntax for UPDATE FROM.
Assuming that BackupKeyID is identity in the PersonBackup table, you may try update statement with the output clause followed by insert of the records not existing in the target table:
update p
set p.Name = s.Name, p.Addr = s.Addr
output deleted.Name, deleted.Addr,
deleted.SSN, deleted.PrimaryKeyID into PersonBackup
from Source s
join Person p on p.SSN = s.SSN;
insert into Person (Name, Addr, SSN)
select s.Name, s.Addr, s.SSN
from Source s
where not exists (select 1 from Person where SSN = s.SSN);
or using insert into ... from (merge ... output) construct in a single statement:
insert into PersonBackup
select Name, Addr, SSN, PrimaryKeyID
from
(
merge Person p
using (select Name, Addr, SSN from Source) s
on p.SSN = s.SSN
when matched then
update set p.Name = s.Name, p.Addr = s.Addr
when not matched then
insert (Name, Addr, SSN) values (s.Name, s.Addr, s.SSN)
output $action, deleted.Name, deleted.Addr, deleted.SSN, deleted.PrimaryKeyID)
as U(Action, Name, Addr, SSN, PrimaryKeyID)
where U.Action = 'UPDATE';
DECLARE #TEMP TABLE (SSN VARCHAR(100),Name VARCHAR(MAX),Addr VARCHAR(MAX) ),
#SSN VARCHAR(100),
#Name VARCHAR(MAX),
#ADDR VARCHAR(MAX)
//INSERT YOUR VALUES INTO THIS TEMP VARIABLE FIRST.
SET #SSN = (SELECT SSN FROM #TEMP)
SET #Name = (SELECT NAME FROM #TEMP)
SET #Addr = (SELECT ADDR FROM #TEMP)
IF EXISTS (SELECT 1 FROM Person_table WHERE SSN = #SSN)
BEGIN
//BACKUP FIRST
INSERT INTO PersonBackup_table
SELECT * FROM Person_table WHERE SSN = #SSN
//UPDATE NEXT
UPDATE A
SET A.NAME = #NAME,
A.ADDR = #ADDR
FROM Person_table A
WHERE A.SSN = #SSN
END
ELSE
BEGIN
INSERT INTO Person_table VALUES #Name,#Addr,#SSN
END

Trigger After Update SQL

I have Customer table. To simplify lets say i have two columns
Id
Name
I have a second table (Log) that I want to update ONLY when the Id column of my customer changes. Yes you heard me right that the primary key (Id) will change!
I took a stab but the NewId that gets pulled is the first record in the Customer table not the updated record
ALTER TRIGGER [dbo].[tr_ID_Modified]
ON [dbo].[customer]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF UPDATE (Id)
BEGIN
UPDATE [log]
SET NewId = Id
FROM customer
END
END
Many would make the argument that if you are changing PK values, you need to rethink the database/table design. However, if you need a quick & dirty fix, add a column to the customer table that is unique (and not null). Use this column to join between the [inserted] and [deleted] tables in your update trigger. Here's a sample script:
CREATE TABLE dbo.Customer (
Id INT CONSTRAINT PK_Customer PRIMARY KEY,
Name VARCHAR(128),
UQColumn INT IDENTITY NOT NULL CONSTRAINT UQ_Customer_UQColumn UNIQUE
)
CREATE TABLE dbo.[Log] (
CustomerId INT NOT NULL,
LogMsg VARCHAR(MAX)
)
INSERT INTO dbo.Customer
(Id, Name)
VALUES
(1, 'Larry'),
(2, 'Curley'),
(3, 'Moe')
INSERT INTO dbo.[Log]
(CustomerId, LogMsg)
VALUES
(1, 'Larry is cool'),
(1, 'Larry rocks'),
(2, 'Curley cracks me up'),
(3, 'Moe is mean')
CREATE TRIGGER [dbo].[tr_Customer_Upd]
ON [dbo].[customer]
FOR UPDATE
AS
BEGIN
UPDATE l
SET CustomerId = i.Id
FROM inserted i
JOIN deleted d
ON i.UQColumn = d.UQColumn
JOIN [Log] l
ON l.CustomerId = d.Id
END
SELECT *
FROM dbo.[Log]
UPDATE dbo.Customer
SET Id = 4
WHERE Id = 1
SELECT *
FROM dbo.[Log]

Is a table-valued function updatable

I'm a bit confused on the update statement but here's what I have: I have these two employees and their respective alpha numeric codes.
select * from cm.bo.hotlist('08Z')
where State = 'ca'
select * from cm.bo.hotlist('06D')
where State = 'ca'
The table has certain cities associated with each employee, the top select statement has these list of cities associated with '08Z'... let's say.
New York
Chicago
I would like to move those cities to the employee '06D'
How would I got about updating?
The confusing part for me is the table is a table-valued function.
Any help would be greatly appreciated. Thank you.
maybe something like so:
update CITY cm.bo.hotlist('06D')
where CITY in (New York, Chicago)
So what you want is:
Update cm.bo.hotlist('08Z')
set
<EmployeeID Column> = '06D'
where
city in ('New York', 'Chicago')
For everyone who comes here, yes, an in-line table value function is updateable as long as the underlying data set is updateable. A code sample:
IF EXISTS(select * from sys.objects where name = 'test' and schema_id = schema_id('dbo')) BEGIN DROP TABLE dbo.test; END
CREATE TABLE dbo.test(Employee varchar(10), city varchar(10));
CREATE FUNCTION [dbo].[getEmployeeCities] ( #employee varchar(10) RETURNS TABLE AS
RETURN ( SELECT * from test where employee = #employee );
insert into dbo.test select 'A', 'Chicago';
insert into dbo.test select 'B', 'New York';
select * from dbo.test;
update dbo.getEmployeeCities('A')
set Employee = 'B'
where city = 'Chicago';
select * from dbo.test;
Update Tablename
SET employes ='06D'
where CITY IN ('NEW York', 'Chicago')

Trigger insert old values- values that was updated

I need to create trigger in SQL Server 2008 that gone insert all values from one row in which some value was changed into Log table!
For example if i have table Employees that have column id, name , password, and i update this table and insert new value for column name, than i need to insert values that was in table Employees after update in table Log.
How I can do this? Thanks!
In your trigger, you have two pseudo-tables available, Inserted and Deleted, which contain those values.
In the case of an UPDATE, the Deleted table will contain the old values, while the Inserted table contains the new values.
So if you want to log the ID, OldValue, NewValue in your trigger, you'd need to write something like:
CREATE TRIGGER trgEmployeeUpdate
ON dbo.Employees AFTER UPDATE
AS
INSERT INTO dbo.LogTable(ID, OldValue, NewValue)
SELECT i.ID, d.Name, i.Name
FROM Inserted i
INNER JOIN Deleted d ON i.ID = d.ID
Basically, you join the Inserted and Deleted pseudo-tables, grab the ID (which is the same, I presume, in both cases), the old value from the Deleted table, the new value from the Inserted table, and you store everything in the LogTable
Here's an example update trigger:
create table Employees (id int identity, Name varchar(50), Password varchar(50))
create table Log (id int identity, EmployeeId int, LogDate datetime,
OldName varchar(50))
go
create trigger Employees_Trigger_Update on Employees
after update
as
insert into Log (EmployeeId, LogDate, OldName)
select id, getdate(), name
from deleted
go
insert into Employees (Name, Password) values ('Zaphoid', '6')
insert into Employees (Name, Password) values ('Beeblebox', '7')
update Employees set Name = 'Ford' where id = 1
select * from Log
This will print:
id EmployeeId LogDate OldName
1 1 2010-07-05 20:11:54.127 Zaphoid
In SQL Server 2008 you can use Change Data Capture for this. Details of how to set it up on a table are here http://msdn.microsoft.com/en-us/library/cc627369.aspx
createTRIGGER [dbo].[Table] ON [dbo].[table]
FOR UPDATE
AS
declare #empid int;
declare #empname varchar(100);
declare #empsal decimal(10,2);
declare #audit_action varchar(100);
declare #old_v varchar(100)
select #empid=i.Col_Name1 from inserted i;
select #empname=i.Col_Name2 from inserted i;
select #empsal=i.Col_Name2 from inserted i;
select #old_v=d.Col_Name from deleted d
if update(Col_Name1)
set #audit_action='Updated Record -- After Update Trigger.';
if update(Col_Name2)
set #audit_action='Updated Record -- After Update Trigger.';
insert into Employee_Test_Audit1(Col_name1,Col_name2,Col_name3,Col_name4,Col_name5,Col_name6(Old_values))
values(#empid,#empname,#empsal,#audit_action,getdate(),#old_v);
PRINT '----AFTER UPDATE Trigger fired-----.'
ALTER trigger ETU on Employee FOR UPDATE
AS
insert into Log (EmployeeId, LogDate, OldName)
select EmployeeId, getdate(), name
from deleted
go