Solved

Updating multiple rows with my trigger gives me a subquery error

Posted on 2010-11-25
12
318 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
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
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
 

Author Comment

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

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 69

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

PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Hi all, It is important and often overlooked to understand “Database properties”. Often we see questions about "log files" or "where is the database" and one of the easiest ways to get general information about your database is to use “Database p…
SQL Server engine let you use a Windows account or a SQL Server account to connect to a SQL Server instance. This can be configured immediatly during the SQL Server installation or after in the Server Authentication section in the Server properties …
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.

815 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

12 Experts available now in Live!

Get 1:1 Help Now