|
database
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Cursor loop is brokenfrom Table1. Each record in the cursor is inserted into Table2. Insert trigger on Table2 is inserting the record into Table3 (in another DB). In the insert trigger on Table3, a series on checks are done on the inserted record and in case of an error, an email is sent and the trigger returns. This break the cursorloop in SP1 and the rest of the records in the cursor is not treated. How do I make sure that all records are treated? This is the flow: -- SP1 --------------------------------- DECLARE csrListe CURSOR FOR SELECT felt1 FROM Table1 OPEN csrListe -- The first record is treated here.... : -- Treat the restWHILE @@FETCH_STATUS = 0 BEGIN FETCH NEXT FROM csrListe INTO @feltet IF @@FETCH_STATUS = 0 BEGIN blah-blah-blah INSERT INTO Table2 (Ordrenr, Status, Dato, Resultat) VALUES (@Ordrenr, @Status, @Dato, @Result) END END CLOSE csrListe DEALLOCATE csrListe -- Table2_ITrig --------------------------------- INSERT INTO db2.dbo.Table3 SELECT * FROM inserted -- Table3_ITrig --------------------------------- SET NOCOUNT ON DECLARE @STATUS int DECLARE @DATOTID smalldatetime DECLARE @RESULT int SELECT @ORDRENR = (SELECT ORDRENR FROM INSERTED) SELECT @STATUS = (SELECT STATUS FROM INSERTED) SELECT @DATOTID = (SELECT DATO FROM INSERTED) SELECT @RESULT = (SELECT RESULT FROM INSERTED) SET XACT_ABORT ON IF NOT @STATUS IN (1,2,3,4,5,6,9,10) BEGIN SELECT @ERR = 'ERROR - unknown status = ' + CAST(@ORDRENR as char(4)) UPDATE Table3 SET RESULTAT=2 WHERE ORDRENUMMER=@ORDRENR EXEC @rc = master.dbo.xp_smtp_sendmail @FROM = N***@here.dk', @TO = N'***@here.dk', @priority = N'HIGH', @subject = N'Status error', @message = N'Status error', @type = N'text/plain', @server = 'smtp.here.dk' RETURN END The mail is send so it must be the final RETURN that is causing the trouble. sblar wrote:
Show quote > In a stored procedure (SP1) I am looping through a cursor with records Do not use cursors in triggers. Doubly important, do not send email> from Table1. Each record in the cursor is inserted into Table2. > Insert trigger on Table2 is inserting the record into Table3 (in > another DB). > In the insert trigger on Table3, a series on checks are done on the > inserted record and in case of an error, an email is sent and the > trigger returns. > This break the cursorloop in SP1 and the rest of the records in the > cursor is not treated. > How do I make sure that all records are treated? > > This is the flow: > > -- SP1 --------------------------------- > DECLARE csrListe CURSOR FOR SELECT felt1 FROM Table1 > > OPEN csrListe > > -- The first record is treated here.... > : > > -- Treat the rest > WHILE @@FETCH_STATUS = 0 BEGIN > FETCH NEXT FROM csrListe INTO @feltet > IF @@FETCH_STATUS = 0 BEGIN > blah-blah-blah > INSERT INTO Table2 (Ordrenr, Status, Dato, Resultat) VALUES > (@Ordrenr, @Status, @Dato, @Result) > END > END > CLOSE csrListe > DEALLOCATE csrListe > > -- Table2_ITrig --------------------------------- > INSERT INTO db2.dbo.Table3 SELECT * FROM inserted > > -- Table3_ITrig --------------------------------- > SET NOCOUNT ON > > DECLARE @STATUS int > DECLARE @DATOTID smalldatetime > DECLARE @RESULT int > > > SELECT @ORDRENR = (SELECT ORDRENR FROM INSERTED) > SELECT @STATUS = (SELECT STATUS FROM INSERTED) > SELECT @DATOTID = (SELECT DATO FROM INSERTED) > SELECT @RESULT = (SELECT RESULT FROM INSERTED) > > SET XACT_ABORT ON > > > IF NOT @STATUS IN (1,2,3,4,5,6,9,10) BEGIN > SELECT @ERR = 'ERROR - unknown status = ' + CAST(@ORDRENR as char(4)) > UPDATE Table3 SET RESULTAT=2 WHERE ORDRENUMMER=@ORDRENR > > EXEC @rc = master.dbo.xp_smtp_sendmail > @FROM = N***@here.dk', > @TO = N'***@here.dk', > @priority = N'HIGH', > @subject = N'Status error', > @message = N'Status error', > @type = N'text/plain', > @server = 'smtp.here.dk' > > RETURN > END > > The mail is send so it must be the final RETURN that is causing the > trouble. from a trigger. See: http://groups.google.co.uk/group/microsoft.public.sqlserver.programming/browse_frm/thread/ab82308c47ed78/2b273c91159441f2 -- David Portas SQL Server MVP -- Thanks David.
The cursor is in the sp not the trigger. I understand your point about email though, and I will consider another path. But, this doesn't seem to be the problem here as the email is sent. Thanks David, I understand your point about email and will consider
another path, but the problem here doesn't seem to be the email which is sent ok. The cursor is in the sp not the trigger. /Søren "Søren Larsen" <sbl***@surfpost.dk> wrote in message Thanks David, I understand your point about email and will considernews:1136633487.767264.30440@g49g2000cwa.googlegroups.com... another path, but the problem here doesn't seem to be the email which is sent ok. The cursor is in the sp not the trigger. /Søren First, I suggest you get rid of the cursor. Use an INSERT ... SELECT statement instead: INSERT INTO Table2 (Ordrenr, Status, Dato, Resultat) SELECT Ordrenr, Status, Dato, Resultat FROM ... ? I expect there was more processing that you left out of your post but I can only suggest a solution for what you posted. Secondly, you need to modify your trigger to handle multiple rows properly. Example: /* This will FAIL if more than one row is inserted/updated */ SELECT @ORDRENR = (SELECT ORDRENR FROM INSERTED) If you don't send emails from the trigger then you won't need to assign the column values to variables. -- David Portas SQL Server MVP -- David Portas (REMOVE_BEFORE_REPLYING_dpor***@acm.org) writes:
Show quote > First, I suggest you get rid of the cursor. Use an INSERT ... SELECT Hey, I've already said all of that! (Except the point of not sending> statement instead: > > INSERT INTO Table2 (Ordrenr, Status, Dato, Resultat) > SELECT Ordrenr, Status, Dato, Resultat > FROM ... ? > > I expect there was more processing that you left out of your post but I > can only suggest a solution for what you posted. > > Secondly, you need to modify your trigger to handle multiple rows > properly. > Example: > > /* This will FAIL if more than one row is inserted/updated */ > SELECT @ORDRENR = (SELECT ORDRENR FROM INSERTED) > > If you don't send emails from the trigger then you won't need to assign > the column values to variables. mail from a trigger.) But I said it in a different newsgroup, as Søren posted the message independently to two newsgroups. With the result that I and David waste our time to say the same thing. Please do not do that again! -- Erland Sommarskog, SQL Server MVP, esq***@sommarskog.se Books Online for SQL Server 2005 at http://www.microsoft.com/technet/prodtechnol/sql/2005/downloads/books.mspx Books Online for SQL Server 2000 at http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx
Show quote
"Erland Sommarskog" <esq***@sommarskog.se> skrev i en meddelelse Sorry to both of you. I never ment to waste anybodys time. I'm new to news:Xns9744C51E0DD29Yazorman@127.0.0.1... > David Portas (REMOVE_BEFORE_REPLYING_dpor***@acm.org) writes: >> First, I suggest you get rid of the cursor. Use an INSERT ... SELECT >> statement instead: >> >> INSERT INTO Table2 (Ordrenr, Status, Dato, Resultat) >> SELECT Ordrenr, Status, Dato, Resultat >> FROM ... ? >> >> I expect there was more processing that you left out of your post but I >> can only suggest a solution for what you posted. >> >> Secondly, you need to modify your trigger to handle multiple rows >> properly. >> Example: >> >> /* This will FAIL if more than one row is inserted/updated */ >> SELECT @ORDRENR = (SELECT ORDRENR FROM INSERTED) >> >> If you don't send emails from the trigger then you won't need to assign >> the column values to variables. > > Hey, I've already said all of that! (Except the point of not sending > mail from a trigger.) But I said it in a different newsgroup, as Søren > posted the message independently to two newsgroups. With the result > that I and David waste our time to say the same thing. > > Please do not do that again! > news(!) and thought I would get more responses tis way. I see your point. It will not happen again. Anyway, thanks for your answers. I'm aware of the problem if my trigger receives multiple rows, which it dont cause its only called from my SP with the cursor loop. I would however very much like to avoid this way of processing but I can't see how if I want to do some processing on each row inserted. For example: if Status = 1 set @result = 2 if Status = 2 set @result = 3 update sometable set Status = @Status where number = select number from inserted Any suggestions? Thanks in advance Søren Søren Larsen (sblar1_thisisno***@surfpost.dk) writes:
Show quote > Anyway, thanks for your answers. I'm aware of the problem if my trigger Without knowledge of the business problem, it's difficult to suggest a > receives multiple rows, which it dont cause its only called from my SP > with the cursor loop. I would however very much like to avoid this way > of processing but I can't see how if I want to do some processing on > each row inserted. For example: > > if Status = 1 > set @result = 2 > if Status = 2 > set @result = 3 > > update sometable set Status = @Status where number = select number from > inserted > > Any suggestions? complete solution. But for the particular problem you appear to illustrate you can use the CASE expression: UPDATE a SET result = CASE b.status WHEN 1 THEN 'OK' WHEN 2 THEN 'OK with warnings' WHEN 3 THEN 'Failed' ELSE 'Complete disaster' END FROM a JOIN b ON a.col = b.col -- Erland Sommarskog, SQL Server MVP, esq***@sommarskog.se Books Online for SQL Server 2005 at http://www.microsoft.com/technet/prodtechnol/sql/2005/downloads/books.mspx Books Online for SQL Server 2000 at http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx
Show quote
"Erland Sommarskog" <esq***@sommarskog.se> skrev i en meddelelse Aha - thats neat. Does this mean that inserted are traversed and a.result news:Xns9745A1206A4E9Yazorman@127.0.0.1... > > Without knowledge of the business problem, it's difficult to suggest a > complete solution. But for the particular problem you appear to illustrate > you can use the CASE expression: > > UPDATE a > SET result = CASE b.status > WHEN 1 THEN 'OK' > WHEN 2 THEN 'OK with warnings' > WHEN 3 THEN 'Failed' > ELSE 'Complete disaster' > END > FROM a > JOIN b ON a.col = b.col > would be updated for every row in inserted and can it be done more than once like this? UPDATE a SET result = CASE inserted.status WHEN 1 THEN 'OK' WHEN 2 THEN 'OK with warnings' WHEN 3 THEN 'Failed' ELSE 'Complete disaster' END FROM a JOIN inserted ON a.col = inserted.col UPDATE c SET somefield = CASE inserted.someotherfield WHEN 1 THEN 11 WHEN 2 THEN 12 WHEN 3 THEN 13 ELSE 0 END FROM c JOIN inserted ON c.col = inserted.col Will this do an update of both a and c based on inserted rows? /Søren Søren Larsen (sblar1_thisisno***@surfpost.dk) writes:
Show quote > Aha - thats neat. Does this mean that inserted are traversed and Yes. CASE is extremely powerful when working with set-based operations.> a.result would be updated for every row in inserted and can it be done > more than once like this? > > UPDATE a > SET result = CASE inserted.status > WHEN 1 THEN 'OK' > WHEN 2 THEN 'OK with warnings' > WHEN 3 THEN 'Failed' > ELSE 'Complete disaster' > END > FROM a > JOIN inserted ON a.col = inserted.col > > UPDATE c > SET somefield = CASE inserted.someotherfield > WHEN 1 THEN 11 > WHEN 2 THEN 12 > WHEN 3 THEN 13 > ELSE 0 > END > FROM c > JOIN inserted ON c.col = inserted.col > > Will this do an update of both a and c based on inserted rows? The above is a simplifed form. The more general form is like this: CASE WHEN somecolumn IN (1, 2, 3) THEN 'This' WHEN othercolumn = 'A' AND somecolumn = 34 THEN 'That' WHEN somecolumn < 0 THEN CASE col WHEN 1 THEN 'J' ELSE 'N' END END So you can test for more general conditions, and you can nest CASE. The conditions are always evaluated top-down, and evaluation stops as soon one matches. If no condition is true, and there is on ELSE, the value is NULL. Important to understand is that CASE is an *expression*, and as a an expression it always return the same data type. If you try: CASE something WHEN 1 THEN 0 ELSE 'x' END this will fail, when something is not 1, because this CASE expression returns an integer value, as integer is higher than char in the data-type precedence in SQL Server. > I almost forgot; why is the cursorloop broken in the first place? There Was there a ROLLBACK? A rollback in a trigge aborts execution.> was no error in trigger, unless RETURN is considered an error! -- Erland Sommarskog, SQL Server MVP, esq***@sommarskog.se Books Online for SQL Server 2005 at http://www.microsoft.com/technet/prodtechnol/sql/2005/downloads/books.mspx Books Online for SQL Server 2000 at http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx
Show quote
"Erland Sommarskog" <esq***@sommarskog.se> skrev i en meddelelse Thats great, thank you Erland, I will try this to avois all my bad news:Xns9745F24504C83Yazorman@127.0.0.1... > Yes. CASE is extremely powerful when working with set-based operations. > The above is a simplifed form. The more general form is like this: > > CASE WHEN somecolumn IN (1, 2, 3) THEN 'This' > WHEN othercolumn = 'A' AND somecolumn = 34 THEN 'That' > WHEN somecolumn < 0 THEN CASE col WHEN 1 THEN 'J' ELSE 'N' END > END > > So you can test for more general conditions, and you can nest CASE. > The conditions are always evaluated top-down, and evaluation stops > as soon one matches. If no condition is true, and there is on ELSE, > the value is NULL. > > Important to understand is that CASE is an *expression*, and as a > an expression it always return the same data type. If you try: > > CASE something WHEN 1 THEN 0 ELSE 'x' END > > this will fail, when something is not 1, because this CASE expression > returns an integer value, as integer is higher than char in the > data-type precedence in SQL Server. > >> I almost forgot; why is the cursorloop broken in the first place? There >> was no error in trigger, unless RETURN is considered an error! > > Was there a ROLLBACK? A rollback in a trigge aborts execution. > structured triggers. BTW there was no rollback, just the RETURN which I thought would go right back to the "caller" and take the next record. This is the way I expect things to work. Seen from a general programming view, a loop can only be broken from within the loop itself, unless there is an error that brings the application to a stop. Sorry, but I'm not sure what happened exactly with all the identical postings! Søren Larsen (sblar1_thisisno***@surfpost.dk) writes:
> BTW there was no rollback, Unless xp_smtp_sendmail issues one.> just the RETURN which I thought would go right back to the "caller" and Well, it is not the loop as such that it is broken, it's the entire> take the next record. This is the way I expect things to work. Seen from > a general programming view, a loop can only be broken from within the > loop itself, unless there is an error that brings the application to a > stop. batch. Anyway, without the complete code, and a reproducible scenario, I cannot give any better answer to the question that I have given now. -- Erland Sommarskog, SQL Server MVP, esq***@sommarskog.se Books Online for SQL Server 2005 at http://www.microsoft.com/technet/prodtechnol/sql/2005/downloads/books.mspx Books Online for SQL Server 2000 at http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx "Erland Sommarskog" <esq***@sommarskog.se> skrev i en meddelelse I know. I appreciate your effort and will carry on from here.news:Xns97471828EF1FYazorman@127.0.0.1... > Anyway, without the complete code, and a reproducible scenario, I cannot > give any better answer to the question that I have given now. > /Søren I almost forgot; why is the cursorloop broken in the first place? There was
no error in trigger, unless RETURN is considered an error! /Søren "Søren Larsen" <sblar1_thisisno***@surfpost.dk> skrev i en meddelelse I found the problem. There was no rollback but another cursor was invoked news:ODWS5zJFGHA.3036@tk2msftngp13.phx.gbl... >I almost forgot; why is the cursorloop broken in the first place? There was >no error in trigger, unless RETURN is considered an error! > > /Søren during the process and I forgot to save @@FETCH_STATUS after each FETCH!!! Need I say more? /Søren Søren Larsen (sblar1_thisisno***@surfpost.dk) writes:
> I found the problem. There was no rollback but another cursor was invoked See, had you posted the full code from the beginning, we would have spotted> during the process and I forgot to save @@FETCH_STATUS after each FETCH!!! > Need I say more? this last week! :-) -- Erland Sommarskog, SQL Server MVP, esq***@sommarskog.se Books Online for SQL Server 2005 at http://www.microsoft.com/technet/prodtechnol/sql/2005/downloads/books.mspx Books Online for SQL Server 2000 at http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx "Erland Sommarskog" <esq***@sommarskog.se> skrev i en meddelelse I know - but the purpose of the code is kind of confidential so it would news:Xns974A4569A57BYazorman@127.0.0.1... > See, had you posted the full code from the beginning, we would have > spotted > this last week! :-) > have meant a lot of work for me to obscure it. I couldn't just leave parts out, as I had no idea where the error was. Also I wouldn't have benefitted from your excellent advice on CASE :o) /Søren Hi David.
I know it's a bad thing to use cursors and I would really like to avoid it. In this case I can't see how as I have to do a lot more processing (as you expect) to each record and therefor have to make sure the trigger receives one row at a time. How could that be done if the trigger received multiple rows? For example: if Status = 1 set somefield = 2 if Status = 2 set somefield = 3 and so on.... Thanks in advance. Søren Hi David.
I know it's a bad thing to use cursors and I would really like to avoid it. In this case I can't see how as I have to do a lot more processing (as you expect) to each record and therefor have to make sure the trigger receives one row at a time. How could that be done if the trigger received multiple rows? For example: if Status = 1 set somefield = 2 if Status = 2 set somefield = 3 and so on.... Thanks in advance. Søren Hi David.
I know it's a bad thing to use cursors and I would really like to avoid it. In this case I can't see how as I have to do a lot more processing (as you expect) to each record and therefor have to make sure the trigger receives one row at a time. How could that be done if the trigger received multiple rows? For example: if Status = 1 set somefield = 2 if Status = 2 set somefield = 3 and so on.... Thanks in advance. Søren Hi David.
I know it's a bad thing to use cursors and I would really like to avoid it. In this case I can't see how as I have to do a lot more processing (as you expect) to each record and therefor have to make sure the trigger receives one row at a time. How could that be done if the trigger received multiple rows? For example: if Status = 1 set somefield = 2 if Status = 2 set somefield = 3 and so on.... Thanks in advance. Søren |
|||||||||||||||||||||||