where condition in Insert/Update Trigger not working - sql

This is my trigger:
Create trigger Points
on Posts
after insert, update
As
declare #Id int;
declare #value int;
select #value= Count(i.Message) from Posts i;
select #Id = [PostedBy] from inserted;
update AspNetUsers set User_points = #value * 3
where #Id = #Id
Here, at the last line, where condition always fails.Its not picking correct Id and updating same value in User_Points column in all rows not in particular rows.
I have written an insert statement to check what value i get back like this:
insert into Employee_Demo(PostedBy, TotalCount)
values (#postedby,#value );
here, i am getting correct #postedby value in table.
Previosly, i was trying this:
create trigger Points
on Posts
after insert, update
As
declare #value int
declare #postedby int
select #value= Count(Message) from Posts
select #postedby = PostedBy from inserted
update AspNetUsers set User_points = #value * 3
where Id = #postedby
please please someone help me. how to update only single row based on Id.
One more thing, PostedBy is not the primary key in post table.It is foreign key to aspnetuser table and it contains id value of user who has posted the message as u can see in below image.
tried this too:
update AspNetUsers set User_points = #value * 3
FROM INSERTED INNER JOIN Posts ON INSERTED.PostedBy = Posts.PostedBy
INNER JOIN AspNetUsers ON AspNetUsers.Id = inserted.PostedBy

Currently, you are comparing same Variable in where clause, where you are supposed to compare DB field with Variable.

Finally got it working with this query dont know how it happens
update AspNetUsers set User_points = #value * 3
where Id = (Select PostedBy from inserted)
and removing the declaration of #Id or #PostedBy. when i declared those variable and then assign value from inserted to those variable and then use that variable value in where then it was not working.
Instead, directly getting value from inserted table in where condition works.

Related

Enumerate the multiple rows in a multi-update Trigger

I have something like the table below:
CREATE TABLE updates (
id INT PRIMARY KEY IDENTITY (1, 1),
name VARCHAR (50) NOT NULL,
updated DATETIME
);
And I'm updating it like so:
INSERT INTO updates (name, updated)
VALUES
('fred', '2020-11-11),
('fred', '2020-11-11'),
...
('bert', '2020-11-11');
I need to write an after update Trigger and enumerate all the name(s) that were added and add each one to another table but can't work out how enumerate each one.
EDIT: - thanks to those who pointed me in the right direction, I know very little SQL.
What I need to do is something like this
foreach name in inserted
look it up in another table and
retrieve a count of the updates a 'name' has done
add 1 to the count
and update it back into the other table
I can't get to my laptop at the moment, but presumably I can do something like:
BEGIN
SET #count = (SELECT UCount from OTHERTAB WHERE name = ins.name)
SET #count = #count + 1
UPDATE OTHERTAB SET UCount = #count WHERE name = ins.name
SELECT ins.name
FROM inserted ins;
END
and that would work for each name in the update?
Obviously I'll have to read up on set based SQL processing.
Thanks all for the help and pointers.
Based on your edits you would do something like the following... set based is a mindset, so you don't need to compute the count in advance (in fact you can't). It's not clear whether you are counting in the same table or another table - but I'm sure you can work it out.
Points:
Use the Inserted table to determine what rows to update
Use a sub-query to calculate the new value if its a second table, taking into account the possibility of null
If you are really using the same table, then this should work
BEGIN
UPDATE OTHERTAB SET
UCount = COALESCE(UCount,0) + 1
WHERE [name] in (
SELECT I.[name]
FROM Inserted I
);
END;
If however you are using a second table then this should work:
BEGIN
UPDATE OTHERTAB SET
UCount = COALESCE((SELECT UCount+1 from OTHERTAB T2 WHERE T2.[name] = OTHERTAB.[name]),0)
WHERE [name] in (
SELECT I.[name]
FROM Inserted I
);
END;
Using inserted and set-based approach(no need for loop):
CREATE TRIGGER trg
ON updates
AFTER INSERT
AS
BEGIN
INSERT INTO tab2(name)
SELECT name
FROM inserted;
END

Delete trigger and getting field from another table

I have this delete trigger on an SQL database. The record deletes currently and gets written to an audit table. I have been asked to include in this history table a field from another table that is related to the record being deleted based on SurveyID. I thought I could do something like
select #Status = Status from table where Survey = deleted.Survey
But this is incorrect syntax.
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
Declare #SurveyId int
Declare #StudentUIC varchar(10)
Declare #Status varchar(10)
select #SurveyId = deleted.SurveyID,
#StudentUIC = deleted.StudentUIC
from deleted
select #Status = Status from tbly when SurveyID = deleted.SurveyID
insert into fupSurveyAudit
values(#SurveyId,#StudentUIC,#Status)
End
Arrgh. I think you want this insert in your trigger (and nothing else):
insert into fupSurveyAudit(SurveyId, StudentUIC, status)
select d.SurveyId, d.StudentUIC, y.status
from deleted d left join
tbly y
on d.SurveyId = y.SurveyId;
Notes:
deleted could contain more than one row, so assuming that it has one row can lead to a run-time error or incorrect results.
A left join is needed in case there is no matching row for the status.
You should always include the columns in an insert
Your archive table should have additional columns, such as an identity column and the date of the insert, which are set automatically (and hence not explicitly part of the insert).
Triggers are fired once for each statement (Delete,insert,update) not for each row inside the statement.
You cannot use variables here because when multiple lines are deleted from the table only one line will be inserted in the Audit table because the variable can only hold one value.
You just need a simple insert from the deleted table into the Audit table something like this....
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
insert into fupSurveyAudit(SurveyId, StudentUIC,[Status])
select d.SurveyID
,d.StudentUIC
,y.[Status]
from deleted d
INNER JOIN tbly y ON y.SurveyID = deleted.SurveyID
End
Try this
ALTER trigger [dbo].[table_Selfdelete]
on [dbo].[table]
after delete
as
Begin
Set nocount on;
insert into fupSurveyAudit -- Better listed the column list here
select
d.SurveyID, d.StudentUIC, y.Status
from
deleted d JOIN tbly y ON d.SurveyID = y.SurveyID
End

After insert not working

all id columns has auto_increment
In my trigger:
ALTER trigger [dbo].[mytrig]
on [dbo].[requests]
after INSERT, UPDATE
as
begin
declare #MyId1 int
set #MyId1 = (select Id from inserted)
declare #MyId2 int
declare #MyId3 int
if (select column1 from inserted) = 1
begin
insert into [dbo].[contracts] select column1,column2,column3 .... from inserted
set #MyId2 = SCOPE_IDENTITY()
insert into [dbo].[History] select column1,column2,column3 .... from inserted
set #MyId3 = SCOPE_IDENTITY()
insert into [dbo].[contracts_depts](Id_Contract ,column5) select #MyId2,column6 from request_depts where Id_request=#MyId1
insert into [dbo].[History_depts] (Id_InHistory,column5) select #MyId3,column6 from request_depts where Id_request=#MyId1
end
end
#MyId1 returns value only after update but not after insert. Do I have to use scope_identity() or something ?
Your main issue is: you're assuming the triggers is called once per row - that is NOT the case!
The trigger is called once per statement, and if your statement affects multiple rows, the Inserted pseudo table will contain multiple rows - so your statement here
set #MyId1 = (select Id from inserted)
really isn't going to work - it will select one arbitrary row (out of however many there are).
You'll need to rewrite your trigger to take this fact into account! Assume that Inserted contains 100 rows - how do you want to deal with that? What are you trying to achieve? Triggers don't return values - they will record into an audit table, or update other rows, or something like that ....

SQL Insert, Update Trigger - Can you update the inserted table?

I have an SQL Trigger FOR INSERT, UPDATE I created which basically does the following:
Gets a LineID (PrimaryID for the table) and RegionID From the Inserted table and stores this in INT variables.
It then does a check on joining tables to find what the RegionID should be and if the RegionID is not equal what it should be from the Inserted table, then it should update that record.
CREATE TRIGGER [dbo].[TestTrigger]
ON [dbo].[PurchaseOrderLine]
FOR INSERT, UPDATE
AS
-- Find RegionID and PurchaseOrderLineID
DECLARE #RegionID AS INT
DECLARE #PurchaseOrderLineID AS INT
SELECT #RegionID = RegionID, #PurchaseOrderLineID = PurchaseOrderLineID FROM Inserted
-- Find PurchaserRegionID (if any) for the Inserted Line
DECLARE #PurchaserRegionID AS INT
SELECT #PurchaserRegionID = PurchaserRegionID
FROM
(...
) UpdateRegionTable
WHERE UpdateRegionTable.PurchaseOrderLineID = #PurchaseOrderLineID
-- Check to see if the PurchaserRegionID has a value
IF #PurchaserRegionID IS NOT NULL
BEGIN
-- If PurchaserRegionID has a value, compare it with the current RegionID of the Inserted PurchaseOrderLine, and if not equal then update it
IF #PurchaserRegionID <> #RegionID
BEGIN
UPDATE PurchaseOrderLine
SET RegionID = #PurchaserRegionID
WHERE PurchaseOrderLineID = #PurchaseOrderLineID
END
END
The problem I have is that it is not updating the record and I'm guessing, it is because the record hasn't been inserted yet into the PurchaseOrderLine table and I'm doing an update on that. But can you update the row which will be inserted from the Inserted table?
The major problem with your trigger is that it's written in assumption that you always get only one row in INSERTED virtual table.
SQL Server triggers are statement-triggers not row-triggers. You have to take that fact into consideration.
Now if I understand correctly the logic behind this trigger then you need just one update statement in it
CREATE TRIGGER TestTrigger ON PurchaseOrderLine
FOR INSERT, UPDATE
AS
UPDATE l
SET RegionID = u.PurchaserRegionID
FROM PurchaseOrderLine l JOIN INSERTED i
ON l.PurchaseOrderLineID = i.PurchaseOrderLineID JOIN
(
SELECT PurchaseOrderLineID, PurchaserRegionID
FROM UpdateRegionTable -- !!! change this for your proper subquery
) u ON l.PurchaseOrderLineID = u.PurchaseOrderLineID
For this example I've created a fake table UpdateRegionTable. You have to change it to the proper query that returns PurchaseOrderLineID, PurchaserRegionID (in your code you replaced it with ...). Make sure that it returns all necessary rows, not one.
Here is SQLFiddle demo
I think the problem could be that you are making the update to PurchaceOrderLine inside the trigger that is monitoring updates to the same table as well. Try to alter the trigger to just monitor the inserts, than if this works, you can make some changes or break your trigger on two: one for inserts, another for updates.
This has been resolved. I resolved the problem by adding the trigger to another table as the IF #PurchaserRegionID IS NOT NULL was always false.

How to use trigger for update in SQL Server 2005

I have a table called tbl_gallery which has a column of datatype bit called isActive.
When the user updates the IsActive value, other rows with IsActive = true will be automatically turned to false.
How can do it with updated trigger?
Please help
I think you want something like:
CREATE TRIGGER trgGalleryActive
ON dbo.tbl_gallery
FOR UPDATE
AS
BEGIN
UPDATE g
-- Update all other gallery rows for this same user to false
SET g.IsActive = 0
FROM tbl_gallery g
INNER JOIN inserted i
on g.UserPK = i.UserPK
WHERE
-- However, we don't want current inserted records to be updated
g.TablePK <> i.TablePK
-- As per Marc's comment - don't update existing inactive rows unnecessarily
AND g.IsActive = 1
-- Only if this record is active should any of this happen
AND i.IsActive = 1
END
Trigger for update second table after updated first table :
CREATE TRIGGER update_table_cityUpdated_afterTable_cityUpdate
ON Table_city
AFTER UPDATE AS
BEGIN
DECLARE #cityId AS BIGINT
DECLARE #stateId AS BIGINT
DECLARE #CityName AS NVARCHAR(200)
SELECT #cityId=cityId FROM INSERTED
SELECT #stateId= stateId FROM INSERTED
SELECT #CityName= CityName FROM INSERTED
UPDATE table_cityUpdated
SET
[dbo].[table_cityUpdated].stateId=#stateId,
[dbo].[table_cityUpdated].CityName=#CityName
WHERE [dbo].[table_cityUpdated].cityId=#cityId
END
;