If Exists in trigger - sql-server

Is there a way I can check if a value exists in a table I want to insert into activated by a trigger? If the value does exist, I want nothing to be done and if it doesn't I would like it to be inserted.
This is my current trigger
ALTER TRIGGER [dbo].[Update]
On [dbo].[A]
AFTER UPDATE
AS
Declare #Id int;
SELECT #Id = Issue FROM Inserted
INSERT INTO dbo.[B] (id, problem)
SELECT BugId, ProjectID
FROM dbo.[C]
WHERE BugId = #Id and (projectid = 547)
Many thanks

inserted can contain multiple rows. And left join can be your friend for testing for whether rows already exist:
ALTER TRIGGER [dbo].[Update]
On [dbo].[A]
AFTER UPDATE
AS
INSERT INTO dbo.[B] (id, problem)
SELECT BugId, ProjectID
FROM
dbo.[C]
inner join
inserted i
on
c.BugID = i.Issue
left join
dbo.B
on
B.ID = c.BugID
WHERE
C.projectid = 547 and B.BugID is null

You should do it as described in this SO post. Use an IF statement to check the existence.

Related

SQL Server : AFTER INSERT trigger and INSERT INTO

I want to create a trigger that will fill up my sales history base after firing in the ORDER table.
I am creating a specific order in regular data base and after that this order automatically goes to sales_history database.
Below part works properly.
When I create a new order in regular database my sales_history database is growing with new ID_ORDERS, hooray! :)
ALTER TRIGGER [dbo].[InsertTrig]
ON [dbo].[ORDER]
AFTER INSERT
AS
IF EXISTS (SELECT *
FROM inserted i
WHERE i.ID_TYPE = 1) -- specific order type
BEGIN
INSERT INTO id.dbo.sales_history (id_order)
SELECT i.ID_ORDER FROM inserted i
END
The problem arises when I want join another table. The trigger stops working
ALTER TRIGGER [dbo].[InsertTrig]
ON [dbo].[ORDER]
AFTER INSERT
AS
IF EXISTS (SELECT *
FROM inserted i
WHERE i.ID_TYPE = 1) -- specific order type
BEGIN
INSERT INTO id.dbo.sales_history (id_order, id_item)
SELECT
inserted.ID_ORDER, ORDER_DETAILS.ID_ITEM
FROM
inserted
INNER JOIN
ORDER_DETAILS ON ORDER_DETAILS.ID_ORDER = inserted.ID_ORDER
END
I also tried this way, and still nothing :(
ALTER TRIGGER [dbo].[InsertTrig]
ON [dbo].[ORDER]
AFTER INSERT
AS
IF EXISTS (SELECT *
FROM inserted i
WHERE i.ID_TYPE = 1) -- specific order type
BEGIN
DECLARE #xyz AS numeric(18, 0)
SET #xyz = (SELECT inserted.ID_ORDER FROM inserted)
INSERT INTO id.dbo.sales_history (id_order, id_item)
SELECT
ORDER.ID_ORDER, ORDER_DETAILS.ID_ITEM
FROM
ORDER
INNER JOIN
ORDER_DETAILS ON ORDER_DETAILS.ID_ORDER = ORDER.ID_ORDER
WHERE
ORDER.ID_ORDER = #xyz
END
I want to create a trigger that will automatically fill up my sales history base after firing in ORDER table.
Your trigger is on the Order table, meaning SQL Server fires it after you insert records into the Order table. At which point, the relevant records in the Order_Details table couldn't have been inserted yet, because they have a foreign key to the Order table.
This is why an inner join between your inserted table and the Order_details table returns 0 rows.
If you want your sales_history from the order_details table, you have to populate it after you insert the records to the order_details table.
CREATE OR ALTER TRIGGER [dbo].[OrderDetails_AfterInsert]
ON [dbo].[ORDER_DETAILS]
AFTER INSERT
AS
INSERT INTO id.dbo.sales_history (id_order, id_item)
SELECT
inserted.ID_ORDER, inserted.ID_ITEM
FROM
inserted
INNER JOIN
[ORDER] ON [ORDER].ID_ORDER = inserted.ID_ORDER
WHERE [ORDER].ID_TYPE = 1 -- specific order type
As a side note: InsertTrig is bad name. Note the name of the trigger in my answer - it tells you exactly what this trigger is for, and on what table.

How to set trigger based on update query in SQL Server?

I am trying to set trigger whenever phone is updated in table1 and then do operation like check phone from table2 and if present, pick up the employee code from table2 and then update employee code in table1.
My code for trigger:
CREATE TRIGGER UPDATED_Contact_Trigger
ON table1
AFTER UPDATE
AS
DECLARE #tuid bigint;
DECLARE #phone varchar(15);
DECLARE #employee_code varchar(10);
IF (UPDATE (phone)) --Phone is the Column Name
BEGIN
SELECT #employee_code = i.emp_code
FROM table2 i (nolock)
WHERE i.MOBILE_NO = #phone
UPDATE table1
SET client_code = #employee_code
WHERE tuid= #tuid
END;
This trigger is set, but there is no update on table1 even if I update a contact which is present in table2
You're not even looking at the Inserted or Deleted pseudo tables in your code - how do you want to know what rows have been updated??
Inserted is a pseudo table that contains all updated rows - and it contains the new values after the update operation, while Deleted contains the same rows, but with the old values before the update.
You need to do something like this:
join your Table1 to Inserted to get the rows that were updated (since you didn't show your table structure, I cannot know what your primary key on Table1 is - you need to use that to join to Inserted)
add a join to your Table2 and pick those rows that have been updated, and limit those to the ones that have been updated in the Phone column (by comparing the Inserted.Phone value to Deleted.Phone)
Try this code:
CREATE TRIGGER UPDATED_Contact_Trigger
ON table1
AFTER UPDATE
AS
BEGIN
-- update your base table
UPDATE t1
-- set the client_code to the employee_code from Table2
SET client_code = t2.employee_code
FROM dbo.Table1 t1
-- join to "Inserted" to know what rows were updated - use the primary key
INNER JOIN Inserted i ON t1.(primarykey) = i.(primarykey)
-- join to "Deleted" to check if the "Phone" has been updated (between Deleted and Inserted)
INNER JOIN Deleted d ON i.(primarykey) = d.(primarykey)
-- join to "Table2" to be able to fetch the employee_code
INNER JOIN dbo.Table2 t2 ON t2.mobile_no = t1.phone
-- ensure the "Phone" has changed, between the old values (Deleted) and new values (Inserted)
WHERE i.Phone <> d.Phone;
END;

I would like to know on how to convert Oracle triggers into SQL Server triggers

As I understand, SQL SERVER Triggers does not support FOR EACH ROW. Also I am aware that you have to use inserted tables and deleted tables. Other than that, I have no clue how to write SQL Server triggers. They look so different. Can some help please?
Below is the code for Oracle Triggers
create or replace TRIGGER Ten_Percent_Discount
BEFORE INSERT OR UPDATE ON Bookings
FOR EACH ROW
DECLARE CURSOR C_Passengers IS
SELECT StatusName
FROM Passengers
WHERE PassengerNumber = :NEW.Passengers_PassengerNumber;
l_status_name Passengers.StatusName%TYPE;
BEGIN
OPEN C_Passengers;
FETCH C_Passengers INTO l_status_name;
CLOSE C_Passengers;
Below is what I have written so far. I know I am using the inserted tables wrong
IF l_status_name = 'Regular'
THEN
:New.TotalCost := 0.90 * :New.TotalCost;
END IF;
END;
create TRIGGER Ten_Percent_Discount
ON Customer
FOR INSERT ,UPDATE
AS
DECLARE C_Passengers CURSOR FOR
SELECT StatusLevel
FROM Customer
WHERE CustomerID = inserted.CustomerID
Thanks for all the help in advance.
Table structure for customer
Table structure for Order
Below answer is only for reference purpose that you can use to build gradually towards final solution:
create table dbo.customer
(
customerid varchar(10),
firstname nvarchar(50),
statuslevel varchar(50)
)
go
create table dbo.customerorder
(
orderid varchar(10),
totalprice numeric(5,2),
productid varchar(10),
customerid varchar(10)
)
go
go
create trigger dbo.tr_customer on dbo.customer for insert,update
as
begin
update co
set co.totalprice = .9*co.totalprice
from dbo.customerorder co
inner join inserted i
on co.customerid = i.customerid
where i.statuslevel = 'Standard'
end
go
--test for above code
insert into dbo.customer values (1,'jayesh','')
insert into dbo.customerorder values (1,500.25,1,1)
insert into dbo.customerorder values (1,600.25,2,1)
select * from dbo.customer
select * from dbo.customerorder
update dbo.customer set statuslevel = 'Standard' where customerid = 1
select * from dbo.customer
select * from dbo.customerorder
But what I am pretty sure is that when customer is created for the first time, there will not be any orders to apply discounts on, so you will certainly need UPDATE Trigger as well.

SQL Server trigger IF condition on other table

In SQL Server, is possible to trigger an event based on a SELECT condition in another table?
Let's imaging this trigger in TABLE_1:
FOR INSERT AS
BEGIN
INSERT INTO TABLE_2 (ID, COD_CAT)
SELECT COD_ART,'X3'
FROM INSERTED
This trigger works fine and always.
I would like trigger that insert event only if INSERTED.COD_ART does not already exist in TABLE_2.
Any ideas?
use trigger on table1 and use 'if exists' before insert
...
FOR INSERT AS
BEGIN
IF not EXISTS
(SELECT COD_ART,'X3'
FROM INSERTED A LEFT JOIN TABLE_2 B
ON A.COD_ART = B.COD_ART
WHERE B.COD_ART IS NULL)
BEGIN
INSERT INTO TABLE_2 (ID, COD_CAT)
SELECT COD_ART,'X3'
FROM INSERTED
END
END
You can't have a selective trigger but you can insert selectively. Use LEFT JOIN to insert only non matching rows as below.
INSERT INTO TABLE_2 (ID, COD_CAT)
SELECT COD_ART,'X3'
FROM INSERTED A LEFT JOIN TABLE_2 B
ON A.COD_ART = B.COD_ART
WHERE B.COD_ART IS NULL

trigger not updating sql

Although this is completed successfully on completion, it is not having the desired update.
CREATE TRIGGER Trigger1
On dbo.[table1]
FOR UPDATE
AS
Declare #Id int;
SELECT #Id = Issue_Id FROM dbo.[table1]
INSERT INTO dbo.[storage]
SELECT Id, Title, project, Problem
FROM dbo.[table2]
WHERE Id = #Id
Is there something I am doing wrong or that I can't use variables within the scope of a trigger?
Many thanks
To support multirow updates
CREATE TRIGGER Trigger1 On dbo.[table1] FOR UPDATE
AS
SET NOCOUNT ON
INSERT INTO dbo.[storage]
SELECT t.Id, t.Title, t.project, t.Problem
FROM dbo.[table2] t
JOIN INSERTED I ON t.ID = I.ID
GO
If table2 is actually table1 (which makes more sense: how is table1 related to storage and table2?)...
CREATE TRIGGER Trigger1 On dbo.[table1] FOR UPDATE
AS
SET NOCOUNT ON
INSERT INTO dbo.[storage]
SELECT Id, Title, project, Problem
FROM INSERTED
GO
To handle multple updates and the inserted table in one go:
CREATE TRIGGER Trigger1
On dbo.[table1]
FOR UPDATE
AS
INSERT INTO dbo.[storage]
SELECT Id, Title, project, Problem
FROM dbo.[table2] t2
JOIN Inserted i ON i.Issue_ID = t2.Id
Please go through the below suggestion.
Instead of the below line
SELECT #Id = Issue_Id FROM dbo.[table1]
It had to be following.
SELECT Issue_Id FROM Inserted
Following is the updated one.
CREATE TRIGGER Trigger1
On dbo.[table1]
FOR UPDATE
AS
SET NOCOUNT ON
Declare #Id int;
With CTE as
(
SELECT Issue_Id FROM Inserted I
Inner Join [table1] T on T.Issue_Id = I.Issue_Id
)
INSERT INTO dbo.[storage]
SELECT Id, Title, project, Problem
FROM dbo.[table2]
Inner Join CTE c on c.Issue_Id = Id
For more information
In SQL server the records which are being inserted / modified or deleted occupies themselves in two temporary tables available in a DML trigger. These tables are INSERTED and DELETED. The INSERTED table has inserted or updated records. The DELETED table has the old state of the records being updated or deleted.
The others have correctly answered that you should be using inserted and a join, to build a proper trigger. But:
Based on your comments to other's answers - you should never attempt to access any resource outside of your own database from a trigger, let along from another server.
Try to decouple the trigger activity from the cross server activity - say have your trigger add a row to a queue table (or use real service broker queues), and have an independent component be responsible for servicing these requests.
Otherwise, if there are any e.g. network issues, not only does your trigger break, but it forces a rollback for the original update also - it makes your local database unusable.
This also means that the independent component can cope with timeouts, and perform appropriate retries, etc.
below line should be removed
SELECT #Id = Issue_Id FROM dbo.[table1]
It should be following.
SELECT Issue_Id FROM Inserted

Resources