How to run SQL trigger - sql-server

I am completely new to SQL Server 2008 and I wrote a trigger and would like to be executed only of hassubproduct and spdisplaytype columns are updated or inserted and if they have a value and are not empty.
Any help is appreciated.
CREATE TRIGGER [dbo].[hassubproductcheck]
ON [dbo].[products]
WITH EXECUTE AS CALLER
FOR INSERT, UPDATE
AS
BEGIN
UPDATE products
SET hassubproduct = LTRIM(RTRIM(hassubproduct))
UPDATE products
SET spdisplaytype = LTRIM(RTRIM(spdisplaytype))
END
GO

Something along these lines is probably more like what you want.
CREATE TRIGGER [dbo].[hassubproductcheck] ON [dbo].[products]
WITH EXECUTE AS CALLER FOR INSERT, UPDATE
AS BEGIN
Update p
set hassubproduct = LTRIM(RTRIM(i.hassubproduct))
, spdisplaytype = LTRIM(RTRIM(i.spdisplaytype))
from Products p
join inserted i on i.PrimaryKey = p.PrimaryKey
where i.hassubproduct > ''
OR i.spdisplaytype > ''
END

You have to use the below code to define the trigger. This will help for updated. The same way we need to create one for inserted as well.
CREATE TRIGGER [dbo].[hassubproductcheck] ON [dbo].products]
AFTER UPDATE
AS
INSERT INTO DBO.SAMPLE_TRIGGER
SELECT hassubproduct, 'UPDATE(PREVIOUS)' [TABLE-UPDATE] FROM DELETED
GO
CREATE TRIGGER [dbo].[hassubproductcheck] ON [dbo].products]
AFTER UPDATE
AS
INSERT INTO DBO.SAMPLE_TRIGGER
SELECT hassubproduct, 'UPDATE (LATEST)' [TABLE-UPDATE] FROM DELETED
GO

Related

Update trigger causing SQL error "Cannot find the object "XXX" because it does not exist or you do not have permissions."

I am running into what seems to be a permission issue.
I have a database table that I created with a trigger that runs after a row update. These are the commands I used to create the trigger:
CREATE TRIGGER [dbo].[my_table_u]
ON [dbo].[my_table]
after UPDATE
AS
BEGIN
SET nocount ON;
UPDATE my_table
SET
last_updated_by = ( Host_name() + Suser_name() ),
last_updated_dt = Getdate()
FROM my_table
INNER JOIN inserted ON my_table.id = inserted.id
END
ALTER TABLE [dbo].[my_table] ENABLE TRIGGER [my_table_u]
GO
I am able to insert and delete rows from my_table, but whenever I go to update my_table, I get the following SQL error:
Msg 1088, Level 16, State 13, Procedure my_table_u, Line 16
[Batch Start Line 0] Cannot find the object "my_table"
because it does not exist or you do not have permissions.
However, if I drop and recreate the trigger without the last ENABLE TRIGGER command, like so:
CREATE TRIGGER [dbo].[my_table_u]
ON [dbo].[my_table]
after UPDATE
AS
BEGIN
SET nocount ON;
UPDATE my_table
SET
last_updated_by = ( Host_name() + Suser_name() ),
last_updated_dt = Getdate()
FROM my_table
INNER JOIN inserted ON my_table.id = inserted.id
END
/*** NO ENABLE TRIGGER COMMAND HERE ***/
GO
Then I am able to update rows without error.
Would anyone have any ideas what is happening here? Maybe some tips where I can start investigating?
Answering my own question.
The issue was that the ALTER TABLE [dbo].[my_table] ENABLE TRIGGER [my_table_u] line in the original CREATE TIGGER command ended up being part of the update trigger. That is, whenever this trigger ran, it also tried to run ALTER TABLE...ENABLE TRIGGER as well, and my user didn't have ALTER permissions granted.
This was confirmed when I granted the user ALTER permissions on my_table, and the problem went away.
The "correct" solution, as pointed out by Dale K in the comments, is to leave out the ENABLE TRIGGER command completely, or, alternatively, make sure it comes after the GO statement that creates the trigger.

SQL - Setting a Default Value from Trigger

I'm currently working on writing a trigger for my database, with table employee and column dno. Before writing the trigger, I specified dno to have a default value of 1, and in the trigger I want to enforce the default value if the value in dno is to be deleted.
This is what I have so far. It seems pretty straightforward to me, but I feel like I'm missing a lot.
create trigger empdeptfk_delete
on employee
after delete as
begin
update employee
set dno = 1
end
Is there a way I can write set default value instead of set dno = 1? Also, I'm using SQL Server 2012, if that helps. Thanks!
You have to handle the Update trigger instead of the delete trigger, because you need to catch when dno field is being UPDATED.
Here is the code:
CREATE TRIGGER empdeptfk_update ON employee
INSTEAD OF UPDATE
AS
BEGIN
IF UPDATE(dno)
BEGIN
DECLARE #DNO INT
SELECT #DNO = dno
FROM Inserted
IF #DNO IS NULL
SET #DNO = 1
UPDATE employee
SET employee.dno = #DNO
FROM Inserted
WHERE Inserted.employeeID = employee.employeeID
END
END
First create 'trigger before delete' then do the update dno=1 and then do the delete.

looking for procedure instead of trigger which we can schedule as a job

Instead of trigger i am planning to write a procedure which we can run using job which will work same way as TRIGGER
with these two tables in the same way.
how can i do that?
here are my tables with column names
1.tblcal
ID(int,not null)
UID(varchar(10),null)
Desc(varchar(200),null)
Date(datetime,null)
avbl(varchar(5),null)
2.tblEvent
ID(int,notnull)
UID(varchar(10),null)
Desc(varchar(200),null)
Date(datetime,null)
Down is my trigger on tblEvent..
ALTER TRIGGER [dbo].[trU] ON [dbo].[tblEvent]
FOR INSERT
AS
Declare #CuID char(6),
#CuDesc char(40),
#CuDate datetime
SET NOCOUNT ON
Select #CuID = i.UID , #CuDesc=i.Desc, #CuDate=i.Date From Inserted i
If(#CuDesc !='available')
Begin
Update tblCal set avbl='Out', Desc=#CurDesc where cadate=#CuDate and UID=#CuID
ENd
SET NOCOUNT OFF
I have another problem with Desc column.Desc which are going to be in and out Basically we need to update tblcal differently for different descriptions;in that case I don't think trigger is that reliable;Means for example for 10 Desc we need to update in and for other 10 we need to update out
Actually every thursday on the tblevent data is loaded once its loaded it fired a trigger and will update in tblcal.
but my client is looking for a procedure which we can schedule as a job after the tblevent entry done on Thursday.
How can i do with stored procedure?
Procedure
CREATE PROCEDURE dbo.usp_UpdateEventData
AS
BEGIN
SET NOCOUNT ON;
UPDATE C
SET c.avbl = 'Out'
,c.[Desc] = e.[Desc]
FROM [dbo].tblCal C
INNER JOIN [dbo].[tblEvent] e ON c.[UID] = e.[UID]
AND c.cadate = e.[Date] --<-- check if you only want
WHERE e.[Desc] <> 'available' -- to join on date not datetime
END -- CAST both columns to DATE
Also if you are keeping your Trigger as it is you will need to modify the trigger definition to handle multiple Inserts, You can use the same logic as in this procedure to update your trigger definition.
Trigger Fix
ALTER TRIGGER [dbo].[trU] ON [dbo].[tblEvent]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE C
SET c.avbl = 'Out'
,c.[Desc] = i.[Desc]
FROM [dbo].tblCal C
INNER JOIN inserted i ON c.[UID] = i.[UID]
AND c.cadate = i.[Date]
WHERE i.[Desc] <> 'available'
END

SQL Server 2008 Update Trigger

I need to create an update trigger on a table that it also updates the table if certain inserted values are present. Is this possible? I have tried and when the inserted value is present and fires the trigger the trigger does an update and fires itself again. Eventually - deadlock. Is there a way to accomplish this safely?
The Code:
CREATE TRIGGER dbo.trg_updateaddress on dbo.Customers
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #original_source varchar(50)
SELECT #original_source = address_source FROM deleted
IF EXISTS (SELECT * FROM inserted i
INNER JOIN deleted d
ON i.cust_id = d.cust_id
WHERE i.address_source IS NOT NULL
AND (i.[address] <> d.[address]
OR i.address2 <> d.address2
OR i.city <> d.city
OR i.[state] <> d.[state]
OR i.zip <> d.zip
OR i.country <> d.country
OR i.phone <> d.phone
OR i.cell <> d.cell
OR i.email <> d.email))
BEGIN
UPDATE customers
SET address_changed = GETDATE()
END
ELSE
BEGIN
UPDATE customers
SET address_source = #original_source
END
END
One thing that you can do is to disable trigger recursion in your database:
USE [master]
GO
ALTER DATABASE [yourDbName] SET RECURSIVE_TRIGGERS OFF WITH NO_WAIT
GO
This will prevent all triggers in the database from triggering themselves directly, while still allowing them to fire other triggers.
I normally recommend this setting anyway, as recursive triggers is not normally what you want, and a very specialized behavior.
You can prevent the trigger from firing on itself with NESTED_LEVEL
Put this after SET NOCOUNT ON;
IF trigger_nestlevel() < 2
This will prevent the trigger from firing on it's own update.
Note: trigger_nestlevel starts counting at 1 for the first update, so if you want the trigger to only fire once then set it to 2, if you want it to fire twice then set this to 3.

MS SQL trigger instead of update ELSE possible to execute original query?

Here is my trigger
Create TRIGGER [dbo].[tri_before_update]
ON [dbo].[test]
instead of update
AS
BEGIN
SET NOCOUNT ON;
if update (test_a)
begin
*.. my update & insert query*
end
END
create TRIGGER [dbo].[tri_before_update_price]
ON [dbo].[co_ticket]
instead of update
AS
BEGIN
SET NOCOUNT ON;
if update (t_price)
begin
insert into old_price_log (t_id,insert_time,process_id,old_t_price)
select i.t_id,getdate(),2,t_price
from Inserted i,co_ticket t where i.t_id = t.t_id
update t set t_price = i.t_price
from co_ticket t, inserted i
where t.t_id = i.t_id
end
else
begin
-- if update other then (t_price) then the update comand not execute.
-- example when i update t_cancel_flag or t_quantity and etc. end
END
This trigger execute perfectly when i update on column "test_a". HOWEVER, when i update other than column "test_a" it won't be execute. I know i can put "else" command, but i got a lot of column. sometimes will update two other column , sometimes three or four column. I don't wish to update all column everytime. Is it possible ELSE "then execute original query"?
I tried a lot different way but still can't work. :( Please HELP!
create TRIGGER [dbo].[tri_on_update_price]
ON [dbo].[co_ticket]
AS
BEGIN
SET NOCOUNT ON;
if update (t_price)
begin
insert into old_price_log (t_id,insert_time,process_id,old_t_price)
select d.t_id, getutcdate(),2,d.price
from deleted d
END
end
An ordinary after trigger will do just what you want: insert a log of the price change, if the price was updated. No need for INSTEAD OF. You need to look into the deleted pseudo-table to get the old price. Never store local times in a database.

Resources