I need to write a SQL trigger that displays the data from columns from two tables. I need this trigger to flow once my Transactions table has a new row added or an existing row updated. this is what I have so far but it isn't working its just printing blank table whenever the table is amended.
create or alter trigger TransactionInfo
on [dbo].[Transactions]
after insert, update
as
begin
declare #pickupDate date;
declare #returnDate date;
declare #Make varchar (25);
declare #model varchar (25);
declare #tID int;
select #pickupDate, #returnDate, #Make, #model, #tID
from[dbo].[Transactions], [dbo].[CAR]
end
Related
I want to get the value of the row causing the execution of the trigger. So I can pass it (as a parameter) to a stored procedure.
The stored procedure accepts as input a table type which is defined in the script below:
CREATE TYPE PersonTableType AS TABLE
(
Id int primary key,
FirstName nvarchar(50),
LastName nvarchar(50)
)
The procedure (insert in the ArchivePerson table the inserted row from the trigger)
Create PROCEDURE sp1
#PersonType PersonTableType Readonly
As
BEGIN
Insert Into ArchivePerson
Select * From #PersonType
END
How do I declare my trigger?
I tried something like:
Alter TRIGGER insertPerson
ON Person
AFTER Insert
AS
BEGIN
declare #PersonType PersonTableType;
??
Exec sp1 #PersonType
END
The inserted table has the rows which were, well, inserted. It has the same columns with your original [Person] table, so use the appropriate columns:
Alter TRIGGER insertPerson
ON Person
AFTER Insert
AS
BEGIN
declare #PersonType PersonTableType;
insert #PersonType(Id,FirstName,LastName)
select <corresponding columns>
from inserted
Exec sp1 #PersonType
END
I am looking to get the SP run only when the Instructions column has something added or altered.
This code works for updating of the Instructions column
AFTER Update
AS BEGIN
SET NOCOUNT on
if update ([Instructions])
BEGIN
DECLARE #ID INT
SELECT #ID = (SELECT [ID] FROM inserted)
EXEC [dbo].[Gem_AddNoteToDelivery] #ID
END
END
GO
ALTER TABLE [dbo].[DeliveryNote] ENABLE TRIGGER [Gemini_DeliveryNote_AddNote]
GO
My Stored Procedure is this
ALTER PROCEDURE [dbo].[Gem_AddNoteToDelivery]
#ID INT output
AS
BEGIN
SET NOCOUNT ON;
DECLARE #DInst VARCHAR (4000)
DECLARE #DELNN VARCHAR (32)
Select #Dinst = [Instructions],
#DELNN = [DelNoteNumber]
FROM [dbo].[DeliveryNote] WHERE [id]=#ID
INSERT INTO [dbo].[Notes]
--([UserID],[OperatorID],[UserName],[DateDB],[ModuleType],[RecordID],[RecordNo],[Flags],[Details],[Priority],[NotesType])
VALUES
(115,0,'Automation',getdate(),4,#ID,#DELNN,
0x0000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000,#DInst,1,Null)
END
GO
If I alter the Trigger to read
AFTER Update,Insert
then the SP runs for updates to all columns not just the Instructions one.
The database is not mine so I am unable to alter tables.
Any help most appreciated.
I am trying to set up a stored proc that will have three variables
FK_List
String_of_Info
CreateId
I need to insert into the table one entry per foreign key from the FK_List. I was curious what the best way to structure the stored procedure to do this efficiently.
EDIT: Code snippet added
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#FKList VARCHAR(MAX),
#Notes NVARCHAR(1000),
#CreateId VARCHAR(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID], [Notes], [CreateId], [UpdateId])
VALUES (#FKList, <---- this is the problem spot
#Notes, #CreateId, #CreateId)
END
GO
Based off your comments, you simply need a slight edit
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#Notes nvarchar(1000),
#CreateId varchar(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID]
,[Notes]
,[CreateId]
,[UpdateId])
select
someID
,#Notes
,#CreateId
,#CreateId
from FKListTable
END
GO
Here is a simple demo
This will insert a row into your table for each FK reference in the reference table with the parameters you pass in. That's all there is to it!
Here's another demo that may be more clear as I use a GUID for the primary key on the secondary table.
SECOND EDIT
Based off your comments, you will need a string splitter. I have added a common one which was created by Jeff Moden. See the example here
The final proc, after you create the function, will be like below. You need to change the comma in the function to what ever the delimiter is for your application. Also, you should start using table valued parameters.
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#FKList VARCHAR(MAX),
#Notes nvarchar(1000),
#CreateId varchar(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID]
,[Notes]
,[CreateId]
,[UpdateId])
select item
,#Notes
,#CreateId
,#CreateId
from dbo.DelimitedSplit8K(#FKList,',')
END
And you can call it like so:
declare #FKList varchar(1000) = '1,2,3,4,5,6'
declare #Notes varchar(1000) = 'here is my note'
declare #CreatedId int = 1
exec StackOverFlowExample_BulkAdd #FKList, #Notes, #CreatedId
I have one table which consists of one trigger which will be called if any insert or update operation performed on that table.
This trigger will insert a new row in other physical table.
First I am taking the entire data to be inserted into a temporary table and then I am inserting data into my physical table(which has trigger).
After performing insert operation all the records in the temporary table are getting inserted into physical table but the trigger is executing for only first record, for rest of the records it is not executing.
Can anyone please help me with this issue.
NOTE : With cursor it is working fine but for performance issue I don't want to use cursor.
ALTER TRIGGER [dbo].[MY_TRG]
ON [dbo].[T_EMP_DETAILS]
FOR INSERT , UPDATE
AS
BEGIN
IF UPDATE(S_EMPLOYEE_ID)OR UPDATE(S_GRADE_ID)OR UPDATE(D_EFFECTIVE_DATE) OR UPDATE(S_EMPLOYEE_STATUS)
BEGIN
DECLARE #EmpId varchar(6)
DECLARE #HeaderId Int
DECLARE #FYStartYear varchar(4)
DECLARE #EffDate Smalldatetime
DECLARE #UpdatedBy varchar(10)
DECLARE #ActionType varchar(1)
DECLARE #RowCount Int
DECLARE #EmpRowCount Int
DECLARE #AuditRowsCount Int
DECLARE #EMP_STATUS VARCHAR(1)
DECLARE #D_FIN_START_YEAR DATETIME
DECLARE #Food_Count int
SELECT #FYStartYear = CAST(YEAR(D_CURRENT_FY_ST_DATE)AS VARCHAR) FROM dbo.APPLICATION WHERE B_IS_CURRENT_FY = 1
SELECT #UpdatedBy = 'SHARDUL'
select #EmpId = S_EMPLOYEE_ID from inserted
select #HeaderId = N_HEADER_TXN_ID from inserted
select #EffDate = D_EFFECTIVE_DATE from inserted
select #FLEXI_AMT = N_FLEX_BASKET_AMT from inserted
select #EMP_STATUS = S_EMPLOYEE_STATUS from inserted
select #D_FIN_START_YEAR=D_FIN_START_DATE from inserted
SELECT #RowCount = count(*) from T_EMP_DETAILS
WHERE S_EMPLOYEE_ID = #EmpId and
SUBSTRING(CAST(D_EFFECTIVE_DATE AS VARCHAR),1,11) = SUBSTRING(CAST(#EffDate AS VARCHAR),1,11)
BEGIN
exec INSERT_DEFAULT_VALUES #EmpId,#HeaderId,#UpdatedBy
END
That's one of many reasons Bulk is so fast :). Read Bulk Insert syntax and you'll see FIRE_TRIGGERS parameter. Use it.
As I wrote in my comment - you are using inserted in improper way. As written now it will work only for 1 row.
The second one is a WEIRD number of variables, and only few are used, why?
Third - you are using SP in the end of batch, you need to post it's code, I bet there is some insert in it, maybe you could avoid using this SP and insert directly in some table from inserted.
I wish to only pass on changes made to ProjectID to the audit table . If for instance changes are made , but the valve stays the same , then a record is not added to the audit table .
CREATE TRIGGER trgAfterUpdate ON [dbo].[Assets]
FOR UPDATE
AS
declare #assetid int;
declare #assetname nvarchar(max);
declare #projectid int;
declare #audit_action varchar(100);
select #assetid=i.AssetID from inserted i;
select #assetname=i.AssetName from inserted i;
select #projectid=i.ProjectID from inserted i;
if update(ProjectID)
set #audit_action='Updated Record -- After Update Trigger.';
insert into Asset_Test_Audit(AssetID,AssetName,Projectid,Audit_Action,Audit_Timestamp)
values(#assetid,#assetname,#projectid,#audit_action,getdate());
PRINT 'AFTER UPDATE Trigger fired.'
GO
you have to compare the results from inserted table with the deleted table like below:
CREATE TRIGGER trgAfterUpdate ON [dbo].[Assets]
FOR UPDATE
AS
declare #assetid int;
declare #assetname nvarchar(max);
declare #projectid int;
declare #audit_action varchar(100);
select #assetid=i.AssetID from inserted i;
select #assetname=i.AssetName from inserted i;
select #projectid=i.ProjectID from inserted i;
if update(ProjectID) and exists (select * from deleted
where AssetID<>#assetid or AssetName<>#assetname or ProjectID<>#projectid)
begin
set #audit_action='Updated Record -- After Update Trigger.';
insert into Asset_Test_Audit(AssetID,AssetName,Projectid,Audit_Action,Audit_Timestamp)
values(#assetid,#assetname,#projectid,#audit_action,getdate());
PRINT 'AFTER UPDATE Trigger fired.'
end
GO
You might want to do it a bit differently. Inserted and deleted tables hold previous and current states of ALL records updated, and you need to audit them all:
CREATE TRIGGER trgAfterUpdate ON [dbo].[Assets]
AFTER UPDATE
AS
set NoCount ON -- So that your insert does not mess with update rowcount
if update(ProjectID)
begin
insert into Asset_Test_Audit(AssetID, AssetName, Projectid, Audit_Action, Audit_Timestamp)
select AssetID, AssetName, ProjectID, 'Updated Record -- After Update Trigger.', getdate()
from Inserted
where not exists (select null from Deleted where Deleted.AssetID = Inserted.AssetID and Deleted.ProjectID = Inserted.ProjectID)
end
PRINT 'AFTER UPDATE Trigger fired.'
GO
A few pointers: do data retrieval in one select; instead of three selects that retrieve columns from Inserted, use one:
select #assetid=i.AssetID, #assetname=i.AssetName, #projectid=i.ProjectID from inserted i;
update(ColumnName) does not imply that value of that column has changed, but merely states that it participated in update:
update assets set ProjectID = ProjectID
still returns true in if update(ProjectID).
Use begin..end even when not necessary as it will save you a headache down the road. Sadly you will not know about the save, but you will certainly know (and feel the pain) if you don't.