Solved

Updating multiple rows with my trigger gives me a subquery error

Posted on 2010-11-25
12
315 Views
Last Modified: 2012-05-10
I have created the following SQL trigger which always returns an error when I run it on multiple rows, so if have more than 1 row and I execute "UPDATE TSDETAIL SET TSD_SUN=120" I get the error below.  When I execute with the KEY such as "UPDATE TSDETAIL SET TSD_SUN=120 WHERE TSD_KEY=1" , I do not get any errors.

My question is how do I write the trigger to work in both cases.

Msg 512, Level 16, State 1, Procedure UPDATE_TSD_RATES, Line 11
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.

ALTER TRIGGER [dbo].[UPDATE_TSD_RATES] ON [dbo].[TSDETAIL]
AFTER UPDATE
AS
DECLARE @v_rate1 NUMERIC(15,4)
DECLARE @v_rate2 NUMERIC(15,4)
DECLARE @v_min   NUMERIC(11)
DECLARE @tsd_key NUMERIC(11)
DECLARE @tsd_rat NUMERIC(11)

BEGIN
    SET @tsd_key=(SELECT TSD_KEY FROM inserted)
    SET @tsd_rat=(SELECT TSD_RAT FROM inserted)
    SET @v_rate1=(SELECT RAT_RATE1 FROM RATE WHERE RAT_KEY=@tsd_rat)
    SET @v_rate2=(SELECT RAT_RATE2 FROM RATE WHERE RAT_KEY=@tsd_rat)
    SET @v_min = (SELECT TSD_MON+TSD_TUE+TSD_WED+TSD_THU+TSD_FRI+TSD_SAT+TSD_SUN FROM inserted)

    UPDATE [dbo].[TSDETAIL] SET TSD_RATE1=@v_rate1, TSD_RATE2=@v_rate2, TSD_MIN=@v_min
      WHERE [dbo].[TSDETAIL].TSD_KEY = @TSD_KEY
END
0
Comment
Question by:hmstechsupport
  • 5
  • 5
  • 2
12 Comments
 
LVL 19

Expert Comment

by:Bhavesh Shah
ID: 34213208
Hi,

As you also know that

when you run below query

UPDATE TSDETAIL SET TSD_SUN=120

This will update multiple rows.

so  SET @tsd_key=(SELECT TSD_KEY FROM inserted) will failed.

You can put (SELECT TOP 1 TSD_KEY FROM inserted) but this is not right way.

Best thing is update query with parameter.

or why you wanted to update multiple at a time????
0
 

Author Comment

by:hmstechsupport
ID: 34213225
The trigger works fine 1 row at a time, but I need to retroactively update the rows that are already in the table and the easiest way is an update statment.  I could write some PLSQL in a stored procedure to update 1 line at a time, but that seems like a long workaround.
Is there no way to write the TRIGGER in SQL to accomplish this?
0
 
LVL 19

Expert Comment

by:Bhavesh Shah
ID: 34213227
or what you can do is....

You can remove trigger and update directly..

UPDATE TSDETAIL
SET TSD_SUN=120,
 TSD_RATE1=RAT_RATE1,
         TSD_RATE2=RAT_RATE2,
 TSD_MIN = TSD_MON+TSD_TUE+TSD_WED+TSD_THU+TSD_FRI+TSD_SAT+TSD_SUN
from TSDETAIL A INNER JOIN RATE B
ON A.TSD_RAT = B.RAT_KEY
WHERE TSD_KEY=1
0
 
LVL 19

Expert Comment

by:Bhavesh Shah
ID: 34213244
Hi,

It might not be accomplish with trigger, if you can update in single query then that will more beneficial, in terms of performance and debugging view.

As you said I  could write some PLSQL in a stored procedure to update 1 line at a time, but that seems like a long workaround.

- It wont be....i dont think so

0
 

Author Comment

by:hmstechsupport
ID: 34213345
Ok.  I have written the stored procedure to accomplish the update and it works fine and accomplished the immediate solution to the problem, but my question about how to do this in a trigger remains unanswered.  Is there no answer to this?
0
 
LVL 19

Expert Comment

by:Bhavesh Shah
ID: 34213493
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 

Author Comment

by:hmstechsupport
ID: 34213599
Ok.  Thanks Brichsoft.  Unfortunate, but I guess that is the way it works.
0
 
LVL 68

Accepted Solution

by:
Qlemo earned 500 total points
ID: 34213764
Of course that is possible. You do not want to insert records, just update, and that is absolutely feasible. And here we go: The "secret" is to consider INSERTED and DELETED as temporary tables you need to join to. DELETED contains the old record, INSERTED the new one. As you do not need the old values here, we can ignore that one.
ALTER TRIGGER [dbo].[UPDATE_TSD_RATES] ON [dbo].[TSDETAIL] 

AFTER UPDATE 

AS

BEGIN

  UPDATE tbl

     SET TSD_RATE1 = RAT_RATE1 

         TSD_RATE2 = RAT_RATE2

         TSD_MIN   = TSD_MON+TSD_TUE+TSD_WED+TSD_THU+TSD_FRI+TSD_SAT+TSD_SUN

    FROM dbo.TSDETAIL tbl

    JOIN inserted i ON tbl.TSD_KEY = i.TSD_KEY

    JOIN RATE     r ON   i.TSD_RAT = r.RAT_KEY

END

Open in new window

0
 
LVL 19

Expert Comment

by:Bhavesh Shah
ID: 34213834
I didnt said,its not possible.but does it require?

Wen u can do it without trigger then why trigger require?



0
 
LVL 68

Expert Comment

by:Qlemo
ID: 34213854
There are many reasons you want to have a trigger acting on the records you have updated:
* updating a secondary table
* no influence to the programming
* expansions which would else require to have the change done on many code lines
* supporting accumulated columns (like the TSD_MIN here).

The danger with such attempt is that is not directly derivable when seeing the query which tables are involved in a transaction. The RATE table would be part of the transaction, hence locked, though the query does not refer to it.
0
 

Author Comment

by:hmstechsupport
ID: 34213927
Ok.  I had to modify this a little as I do want it to work for Insert and Update so I added the INSERT clause and I had to make a few other minor changes adding commas and adding aliases to avoid ambiguity but this is EXACTLY what I hoped for.  Works like a charm in both inserting new rows and also running a big update statement.
Thank you Qlemo.
I also agree that the reason I do this is to avoid adding code to the application that ther clients do not require.  This trigger suits this client perfectly.

ALTER TRIGGER [dbo].[UPDATE_TSD_RATES] ON [dbo].[TSDETAIL]
AFTER INSERT,UPDATE
AS
BEGIN
  UPDATE tbl
     SET TSD_RATE1 = r.RAT_RATE1,
         TSD_RATE2 = r.RAT_RATE2,
         TSD_MIN   = tbl.TSD_MON+tbl.TSD_TUE+tbl.TSD_WED+tbl.TSD_THU+tbl.TSD_FRI+tbl.TSD_SAT+tbl.TSD_SUN
    FROM dbo.TSDETAIL tbl
    JOIN inserted i ON tbl.TSD_KEY = i.TSD_KEY
    JOIN RATE     r ON   i.TSD_RAT = r.RAT_KEY
END
0
 

Author Closing Comment

by:hmstechsupport
ID: 34213931
Fabulous and exactly what I was looking for.
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

'Between' is such a common word we rarely think about it but in SQL it has a very specific definition we should be aware of. While most database vendors will have their own unique phrases to describe it (see references at end) the concept in common …
In this article I will describe the Detach & Attach method as one possible migration process and I will add the extra tasks needed for an upgrade when and where is applied so it will cover all.
This video discusses moving either the default database or any database to a new volume.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now