1

There's a database table that has an update trigger. Whenever a column is updated, one of its columns is automatically calculated.

I have tweaked the trigger and I'd like to run it on all of the rows again. In SQL Server Management Studio, if I choose "Edit Top 200 Rows" on my table and edit one of the rows, the update trigger works. But when I write a query like:

UPDATE MyTable
SET SomeIrrelevantColumn = 0

the trigger doesn't work, the column that is supposed to be calculated by the trigger stays the same.

How can I run the trigger manually on all the rows?

Edit: Here's the trigger:

USE [MY_DATABASE]
GO
/****** Object:  Trigger [dbo].[MY_TABLE_AUER]    Script Date: 04/24/2013 00:05:23 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[MY_TABLE_AUER] 
   ON  [dbo].[MY_TABLE] 
   AFTER UPDATE
AS 
DECLARE @UPD_COLUMN_A int,
        @INS_COLUMN_A int,
        @UPD_COLUMN_B int,
        @UPD_COLUMN_C varchar(255),
        @UPD_COLUMN_D varchar(255),
        @UPD_COLUMN_E int,
        @UPD_COLUMN_F datetime
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    SELECT @UPD_COLUMN_A = _Column_A,
           @UPD_COLUMN_B =_Column_B,
           @UPD_COLUMN_C = COLUMN_C,
           @UPD_COLUMN_D = [Column_D]
      FROM DELETED;
    IF @UPD_COLUMN_D not like '%SomeString%'
    BEGIN
      SELECT @INS_COLUMN_A = _Column_A
        FROM INSERTED;
      IF @UPD_COLUMN_A != @INS_COLUMN_A
      BEGIN
        SELECT @UPD_COLUMN_E = MAX([_Column_B]),
               @UPD_COLUMN_F = MAX([_Column_G])
          FROM MY_TABLE
         WHERE COLUMN_C = @UPD_COLUMN_C
           AND [Column_D] LIKE '%SomeString%';
        UPDATE MY_TABLE 
           SET COLUMN_E = @UPD_COLUMN_E,
               COLUMN_F = @UPD_COLUMN_F
         WHERE [_Column_B] = @UPD_COLUMN_B;
        UPDATE MY_TABLE 
           SET COLUMN_H = @UPD_COLUMN_B
         WHERE [_Column_B] = @UPD_COLUMN_E; 
      END
    END
END
hattenn
  • 4,371
  • 9
  • 41
  • 80
  • 2
    You'll have to show the trigger code, otherwise all we can do is guess. – Aaron Bertrand Apr 23 '13 at 22:04
  • could be there is an error in the trigger code, perhaps you could post it? – Ian Kenney Apr 23 '13 at 22:05
  • Just added the trigger code. – hattenn Apr 23 '13 at 22:15
  • 5
    Your trigger makes a very common but false assumption that it will execute once per row. It doesn't, it executes once per *action* - so when you update the entire table, I bet if you look closer, you'll see that *one* row was updated. – Aaron Bertrand Apr 23 '13 at 22:23
  • @AaronBertrand, I am just developing the frontend and I have virtually no experience with databases or SQL. How can I fix this problem? – hattenn Apr 23 '13 at 22:29
  • 1
    You can learn how to write SQL code that performs updates against many rows at once instead of one at a time. – ErikE Apr 23 '13 at 22:39
  • @ErikE, I assume that you know how to do that but have no interest in sharing a resource on the subject or adding an answer explaining it, am I correct? – hattenn Apr 23 '13 at 22:43
  • @ErikE, I don't think there are more than a couple thousand questions on this website that include original research, all the others can somehow be "Googled". I could of course go on and start reading about SQL, and then triggers, and then update triggers, and so on. In the end, I could have a comprehensive knowledge on triggers, which would be good of course. But I just wanted to see if anyone could point me in the right direction, so that I could get on my way faster. As I'm not the database manager, I have no interest in learning SQL in detail. – hattenn Apr 23 '13 at 22:53
  • Apart from that, both the resources you pointed me at proudly as your Google results are not that easy to find. If I knew about "Update Based Join" or "Multi-Row Trigger Update" concepts, I probably wouldn't be here asking. "With all due respect", writing "just go learn it" is just being cocky, not helpful. – hattenn Apr 23 '13 at 22:54
  • @hattenn, all questions should show some effort, or as you call it, original research. The official [how to ask](http://stackoverflow.com/questions/how-to-ask) section of the FAQ says: "Do your homework. Have you thoroughly searched for an answer before asking your question? Sharing your research helps everyone. Tell us what you found and why it didn’t meet your needs. This demonstrates that you’ve taken the time to try to help yourself, it saves us from reiterating obvious answers, and most of all it helps you get a more specific and relevant answer!" I am deleting my other comments. – ErikE Apr 23 '13 at 23:00
  • @ErikE, apparently the problem is with deciding on the definition of "showing some effort". Me trying to run this trigger with my very limited knowledge of SQL and trying different ways, trying to see the difference between updating only one row and updating many rows was not enough "showing some effort" for you. Again, I could very well go and start reading from the beginning, I guess it was "wrong" to assume that someone here would just say "hey you know what, that part of your query looks bad to me, check this out." I wish I had time to learn everything in detail, but I don't. – hattenn Apr 23 '13 at 23:11
  • I most humbly apologize for not answering your question the way you wanted. I really thought my comment would be helpful, providing you a search phrase such as "sql update against many rows at once" to lead you to an answer. Comments are drive-by, quick things--I would *never* have posted that comment as an answer. The effort I expected was for you to take my hint and run with it. That no one bothered to explain fully in a real answer is upsetting--I understand that, as someone who's asked questions here fruitlessly. At the same time, consider that I *did* point you in the right direction. – ErikE Apr 24 '13 at 15:54
  • @ErikE, in the end I have solved it using hints from another question that I asked today (http://stackoverflow.com/questions/16191581/updating-each-row-with-some-values-of-another-row). I appreciate any comment that points me in the right direction, and I'm definitely not here expecting people will solve all my problems for me (as you can see from all the questions I have asked). But this is a Q&A site, and when I ask "How can you write an update trigger in SQL for multiple rows?", if you say "Well you can start by learning how to write SQL code that works on multiple rows.", that is just rude – hattenn Apr 24 '13 at 21:03
  • In the end, my problem is not someone trying to point me at the right direction, and it is sad that you are still trying to act like I'm trying to get quick solution to my problems here, which you base on your thought that "I'm just not trying to put any effort and I don't deserve to get anything more than 'just go learn it'". If you think that your tone in your comment was completely appropriate and solely for helping, I definitely don't have anything else to talk about. – hattenn Apr 24 '13 at 21:04
  • @hatten, if you have no desire to learn SQl in detail, you are incompetent to be writing triggers. – HLGEM Apr 24 '13 at 21:46
  • @HLGEM, it's somehow blown extremely out of proportion. First, if I was competent enough to be writing triggers, I wouldn't come here in the first place, I would solve my own problem the way I do for many many things every day. The second thing is, I was writing the frontend for this database and I wanted to try something quick, I wanted make a small change in the trigger so that I could try one little thing, I'm not trying to become a database administrator. Third, even though I have virtually zero knowledge of SQL, as you can see from the answer, I somehow solved it and it works well enough. – hattenn Apr 24 '13 at 21:58

3 Answers3

8

Your trigger makes a very common but false assumption that it will execute once per row. It doesn't, it executes once per action--so when you update the entire table, I bet if you look closer, you'll see that one row was updated. * with thanks to Aaron Bertrand's comment for this intro paragraph.

You'll need to look into how to perform an update based on a JOIN (with the inserted or deleted meta-tables). For example:

CREATE TRIGGER TR_Sample_U ON dbo.Sample FOR UPDATE -- AFTER is default so not needed
AS
IF EXISTS ( --check for disallowed modifications
   SELECT *
   FROM
      Inserted I
      INNER JOIN Deleted D
         ON I.SampleID = D.SampleID
   WHERE
      I.Something <> D.Something
      AND I.UpdateDate = D.UpdateDate
)
ROLLBACK TRAN;

These resources may also help you:

Community
  • 1
  • 1
ErikE
  • 48,881
  • 23
  • 151
  • 196
  • 1
    It's ironic that, without exception, all the links you have pointed me at pretty much share the same style as mine. They just go ahead and tell what's not working and ask if anyone knows a solution to make it work. No "original research". If everyone just acted like you did, none of those answers would exists today. But thanks for sharing them anyways. – hattenn Apr 23 '13 at 23:21
  • And you pushed back--bravo! And you got the answer you need. So are we cool now? – ErikE Apr 24 '13 at 15:55
  • 1
    Regardless of everything, I appreciate you backing down and writing an answer with an appropriate tone. Though, I don't know what you mean by "pushing back" in your comment. – hattenn Apr 24 '13 at 21:05
  • You spoke up for yourself and let me know that you were unhappy with what you were getting. – ErikE Apr 24 '13 at 22:08
0

I have found out that one way to do it is something like the following:

UPDATE A
SET A.SOME_COLUMN = D.ANOTHER_COLUMN
FROM MY_TABLE AS A
JOIN inserted AS B ON A.ID = B.ID -- Point 1.
JOIN deleted AS C ON A.ID = C.ID
JOIN (SELECT MAX(ID) AS OTHER_ID, GROUP_ID AS OTHER_GROUP_ID -- Point 2.
      FROM MY_TABLE AS E
      WHERE E.SOME_STRING_COLUMN LIKE '%SomeString%'
      GROUP BY E.GROUP_ID) AS D ON A.GROUP_ID = D.OTHER_GROUP_ID
WHERE C.SOME_BOOL_COLUMN != B.SOME_BOOL_COLUMN -- Point 3.
      AND C.SOME_STRING_COLUMN NOT LIKE '%SomeString%'
  1. After the basic UPDATE statement, I go ahead and join the table to 'inserted' and 'deleted' special tables (more info about those at http://www.mssqltips.com/sqlservertip/2342/understanding-sql-server-inserted-and-deleted-tables-for-dml-triggers/). This way, I'll only go through the rows that have been updated, and I won't mess with the other ones. You can only join with one of them, but I needed to see a difference in one column between the values before and after the update operation. So that's why I used them both. 'deleted' has the row in the state before the update operation, and 'inserted' has the row in the state after the update operation.
  2. After that, I need to find a row in the whole table that is calculated by a value in the row that is currently being updated. In my case, there was a parent of the current row and I wanted to find that row. Those two rows shared the same GROUP_ID, and I made a string test to make sure that the new row I get is qualified as a parent, you can define any kind of filter there. Basically, you write another query to find the row based on your updated row, and then you make another JOIN to that returned table.
  3. And last, I used a WHERE clause to make sure that I only update the rows that has changed state by looking at the SOME_BOOL_COLUMN column. You can put any kind of criterion here. As you can see I check the difference between the state of the column before and after the update.

Take whatever written here with a grain of salt though, as it's coming from someone that has virtually no experience with SQL.

hattenn
  • 4,371
  • 9
  • 41
  • 80
  • I see that you're getting the `Max` of some value. Are you performing an update with that max value, and if so, are you intending all modified rows to be updated to the same value? Also, if concurrency is possible (multiple clients making modifications at once), then you will need to add `FROM MY_TABLE E WITH (UPDLOCK, HOLDLOCK)` to be sure that two clients don't get the same `Max` value at the same time. This table locking could be a killer to high throughput. [This](http://stackoverflow.com/questions/14967384/computed-column-expression/14970664#14970664) may help if the patterns are similar. – ErikE Apr 25 '13 at 00:21
  • @ErikE, what I wanted to do with that `MAX` was just find the parent row (which shares the same value at the `GROUP_ID` column with the current row being updated), and then just set the parent of the current row to the one that has the maximum `ID`, which is the unique key. So basically, that `MAX(ID)` value ends up being the parent reference of the current row being updated. – hattenn Apr 25 '13 at 00:34
  • Apart from that, even if concurrency is an issue, it's definitely not my issue. It took me a couple hours to get this working this morning. Should it become an issue, someone with more knowledge can take a look at it (I doubt that there's anyone that can handle it where I'm working at, though). But thanks for the input, and the resources you have shared in your answer, they definitely helped. – hattenn Apr 25 '13 at 00:35
-2

Please try using the below code..in trigger..!

//Check if the column is getting updated

if (Update(column1) or Update(Column2)...etc)

Begin

  Write the entire logic inside this loop..!

End

Hope this works..!!!

Kalamarico
  • 5,466
  • 22
  • 53
  • 70