DB2 for i Triggers - Once per statement, but comparing before and after valuesMaterialized Query Table in SQL Server 2005DB2 9.7 statement vs row triggersDB2 Trigger Row LockingHow to make a db2 trigger updates only the inserted row without going through all the recordsHow to get DB2 MQT last refresh timeDB2 update column with incrementing number based on distinct values in another columnDB2 table change trackingUsing a trigger to make a table read-only in DB2Create History Trigger Db2Database DB2 Triggers

Fully-Firstable Anagram Sets

Anagram holiday

Is it possible to run Internet Explorer on OS X El Capitan?

Is it inappropriate for a student to attend their mentor's dissertation defense?

Is there a hemisphere-neutral way of specifying a season?

How is it possible to have an ability score that is less than 3?

How can I fix/modify my tub/shower combo so the water comes out of the showerhead?

What about the virus in 12 Monkeys?

Modeling an IP Address

Brothers & sisters

Facing a paradox: Earnshaw's theorem in one dimension

1960's book about a plague that kills all white people

In a spin, are both wings stalled?

Is it possible to create light that imparts a greater proportion of its energy as momentum rather than heat?

Stopping power of mountain vs road bike

Why "Having chlorophyll without photosynthesis is actually very dangerous" and "like living with a bomb"?

Memorizing the Keyboard

Alternative to sending password over mail?

Infinite Abelian subgroup of infinite non Abelian group example

Why do I get two different answers for this counting problem?

Does a druid starting with a bow start with no arrows?

How to model explosives?

How could indestructible materials be used in power generation?

Were any external disk drives stacked vertically?



DB2 for i Triggers - Once per statement, but comparing before and after values


Materialized Query Table in SQL Server 2005DB2 9.7 statement vs row triggersDB2 Trigger Row LockingHow to make a db2 trigger updates only the inserted row without going through all the recordsHow to get DB2 MQT last refresh timeDB2 update column with incrementing number based on distinct values in another columnDB2 table change trackingUsing a trigger to make a table read-only in DB2Create History Trigger Db2Database DB2 Triggers






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








0















In DB2 for IBM i, is it possible to create a trigger which runs once per statement, but able to loop through all affected rows to determine if any values actually changed?



Use case is to update a Materialized Query Table (MQT) with a trigger on the underlying tables. But we only want to refresh the MQT if values have actually changed. If we create the trigger to run once per row, we are able to get the desired functionality. But if we Insert, Update and/or Delete multiple rows at a time, the "Refresh" statement runs for each row. And currently that takes about 10 seconds for this MQT on our system.



Just hoping there was a way to use a trigger set to run once per statement, yet still have access to the before and after values of each individual row. I haven't been able to find anything which indicates whether it is or isn't possible. Though I suspect it is not.



If there is some other way to automatically refresh MQTs in an efficient manner, I am open to that as well.










share|improve this question




























    0















    In DB2 for IBM i, is it possible to create a trigger which runs once per statement, but able to loop through all affected rows to determine if any values actually changed?



    Use case is to update a Materialized Query Table (MQT) with a trigger on the underlying tables. But we only want to refresh the MQT if values have actually changed. If we create the trigger to run once per row, we are able to get the desired functionality. But if we Insert, Update and/or Delete multiple rows at a time, the "Refresh" statement runs for each row. And currently that takes about 10 seconds for this MQT on our system.



    Just hoping there was a way to use a trigger set to run once per statement, yet still have access to the before and after values of each individual row. I haven't been able to find anything which indicates whether it is or isn't possible. Though I suspect it is not.



    If there is some other way to automatically refresh MQTs in an efficient manner, I am open to that as well.










    share|improve this question
























      0












      0








      0








      In DB2 for IBM i, is it possible to create a trigger which runs once per statement, but able to loop through all affected rows to determine if any values actually changed?



      Use case is to update a Materialized Query Table (MQT) with a trigger on the underlying tables. But we only want to refresh the MQT if values have actually changed. If we create the trigger to run once per row, we are able to get the desired functionality. But if we Insert, Update and/or Delete multiple rows at a time, the "Refresh" statement runs for each row. And currently that takes about 10 seconds for this MQT on our system.



      Just hoping there was a way to use a trigger set to run once per statement, yet still have access to the before and after values of each individual row. I haven't been able to find anything which indicates whether it is or isn't possible. Though I suspect it is not.



      If there is some other way to automatically refresh MQTs in an efficient manner, I am open to that as well.










      share|improve this question














      In DB2 for IBM i, is it possible to create a trigger which runs once per statement, but able to loop through all affected rows to determine if any values actually changed?



      Use case is to update a Materialized Query Table (MQT) with a trigger on the underlying tables. But we only want to refresh the MQT if values have actually changed. If we create the trigger to run once per row, we are able to get the desired functionality. But if we Insert, Update and/or Delete multiple rows at a time, the "Refresh" statement runs for each row. And currently that takes about 10 seconds for this MQT on our system.



      Just hoping there was a way to use a trigger set to run once per statement, yet still have access to the before and after values of each individual row. I haven't been able to find anything which indicates whether it is or isn't possible. Though I suspect it is not.



      If there is some other way to automatically refresh MQTs in an efficient manner, I am open to that as well.







      db2 database-trigger db2-400 materialized-views






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Mar 21 at 18:36









      d.lanza38d.lanza38

      96251636




      96251636






















          3 Answers
          3






          active

          oldest

          votes


















          0














          Example:



          create table test (id int not null primary key, a int)@
          create table test_mqt (cnt) as (select sum(a) from test) data initially deferred refresh deferred maintained by user@

          insert into test values (1, 1), (2, 1), (3, 1) with nc@

          create or replace trigger test_aus
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          if (exists (select 1 from n,o where n.id=o.id and n.a<>o.a)) then
          refresh table test_mqt;
          end if;
          end@

          -- trigger IS NOT fired after the following update
          update test set a=1 with nc@
          -- the following select returns 0
          select cnt from test_mqt@

          -- trigger IS fired after the following update
          update test set a=2 with nc@
          -- the following select returns 6
          select cnt from test_mqt@





          share|improve this answer























          • Okay, so the references to OLD TABLE and NEW TABLE represent a single row at a time, but will always loop through each affected row without explicit iterative structures?

            – d.lanza38
            Mar 21 at 20:25











          • n and o here are the correlation names for the transition tables (new and old sets of affected rows), not individual affected rows. "Loop through each affected row" is made by the SQL select statement in the trigger definition.

            – Mark Barinstein
            Mar 21 at 20:29












          • I don't think having the trigger run a refresh makes sense...see my answer for an alternative.

            – Charles
            Mar 21 at 23:03











          • @Charles My example was essentially on how to detect table changes with a for each statement trigger and run some statement, if they are detected. As for real MQT maintenance with triggers - it may be more complex solution. Obviously, we need after insert and after delete triggers and rewritten after update trigger as well, if we don’t use full refresh at some point, and want to maintain our MQT incrementally.

            – Mark Barinstein
            Mar 22 at 5:56


















          1














          Yes, the documentation is here. However, depending on how you are trying to do this, there are some differences between the IBM i command ADDPFTRG and the SQL CREATE TRIGGER.



          ADDPFTRG does not appear to support statement level triggers but CREATE TRIGGER does.



          When using the statement level trigger, you can reference the affected rows with



          REFERENCING OLD TABLE AS ___
          NEW TABLE AS ___


          You can process the old and new table references with SQL statements just as if they were regular tables.



          Just to be clear, OLD TABLE references affected rows as they were before the SQL statement ran, and NEW TABLE references affected rows as they will be after the SQL statment completes.






          share|improve this answer

























          • Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm using FOR EACH STATEMENT as opposed to FOR EACH ROW, how do I still iterate through each affected row so I can compare the before and after values?

            – d.lanza38
            Mar 21 at 20:03











          • Thank you for trying to clarify. But I'm not sure I understand how to iterate through each row. Would I open a cursor based on the aliases I created in the definition? So a cursor on T1 if it were defined as REFERENCING OLD TABLE AS T1...?

            – d.lanza38
            Mar 21 at 20:21











          • Don't think about it as iterating through. Think in sets. Join them together and select the set of rows with differences. If any differences are returned, you would update your MQT, if the set comes back empty, then don't update the MQT.

            – jmarkmurphy
            Mar 21 at 20:25











          • However, you could still be refreshing that MQT a lot. It seems that if you want to keep things in sync, an MQT may not be the way to go, but rather a view or a table function.

            – jmarkmurphy
            Mar 21 at 20:27











          • Okay, so both OLD TABLE and NEW TABLE share the same structure as the table in question, but only contain the affected records and nothing else. I think I got it now. I was thinking those references represented the entire table, not just the rows which were affected.

            – d.lanza38
            Mar 21 at 20:28


















          0














          I don't think it makes sense to have a trigger run the refresh...



          The whole point of the trigger + MQT would be to have the trigger directly update the MQT table. That way you only have to deal with the exact rows that have changed; rather than force the DB to read the entire base table again.



          create or replace trigger test_aus 
          after update on test
          referencing
          new row as n
          old row as o
          for each row
          mode db2sql
          begin atomic
          if n.a <> o.a then
          update test_mqt set cnt = cnt + n.a - o.a;
          end if;
          end@


          But note that if a change in a is all you are interested in, then you could define the trigger as



          after update of a on test 
          for each row


          that way the trigger will only fire if a is actually updated.



          If you've got more SQL set at a time updates being done than RPG (or SQL) single row updates, then maybe a statement trigger would be worthwhile...



          Something like so:



          create or replace trigger test_aus 
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          update test_mqt
          set cnt = cnt + (select sum(n.a - o.a)
          from N join O using(id)
          where n.a <> o.a
          );

          end@


          Edit: Alternative to MQT

          I've never actually used an MQT in production, since the IBM i doesn't support system maintained MQTs.



          In the scenario where you're interested in an updated aggregate, Encoded Vector Indexes (EVI) with included aggregates may provide a better solution; as they are maintained automatically.



          CREATE ENCODED VECTOR INDEX sales_fact_location_id_evi 
          ON sales_fact(sale_location_id ASC)
          INCLUDE(SUM(sale_amount_measure))


          The example above is from the article Accelerated analytics - faster aggregations using the IBM DB2 for i encoded vector index (EVI) technology . It a good article and compares EVI to MQT for storing aggregates.






          share|improve this answer

























          • As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t have refresh immediate or refresh deferred with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we need after insert and after delete triggers as well. But when things go slightly more complex, such a trigger logic may become too complex very soon, and we finally may decide to end up with a solution like firing full refresh at some point.

            – Mark Barinstein
            Mar 22 at 6:19











          • @MarkBarinstein agree that it is unfortunate that Db2 for i doesn't support system maintained MQT. But if you need real-time updates to MQT, then triggers updating the MQT are the only option. If real-time isn't needed, then a scheduled refresh (with either the refresh statement or a user program) is ok. Having a trigger use the refresh command doesn't make sense.

            – Charles
            Mar 22 at 15:58











          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55287128%2fdb2-for-i-triggers-once-per-statement-but-comparing-before-and-after-values%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0














          Example:



          create table test (id int not null primary key, a int)@
          create table test_mqt (cnt) as (select sum(a) from test) data initially deferred refresh deferred maintained by user@

          insert into test values (1, 1), (2, 1), (3, 1) with nc@

          create or replace trigger test_aus
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          if (exists (select 1 from n,o where n.id=o.id and n.a<>o.a)) then
          refresh table test_mqt;
          end if;
          end@

          -- trigger IS NOT fired after the following update
          update test set a=1 with nc@
          -- the following select returns 0
          select cnt from test_mqt@

          -- trigger IS fired after the following update
          update test set a=2 with nc@
          -- the following select returns 6
          select cnt from test_mqt@





          share|improve this answer























          • Okay, so the references to OLD TABLE and NEW TABLE represent a single row at a time, but will always loop through each affected row without explicit iterative structures?

            – d.lanza38
            Mar 21 at 20:25











          • n and o here are the correlation names for the transition tables (new and old sets of affected rows), not individual affected rows. "Loop through each affected row" is made by the SQL select statement in the trigger definition.

            – Mark Barinstein
            Mar 21 at 20:29












          • I don't think having the trigger run a refresh makes sense...see my answer for an alternative.

            – Charles
            Mar 21 at 23:03











          • @Charles My example was essentially on how to detect table changes with a for each statement trigger and run some statement, if they are detected. As for real MQT maintenance with triggers - it may be more complex solution. Obviously, we need after insert and after delete triggers and rewritten after update trigger as well, if we don’t use full refresh at some point, and want to maintain our MQT incrementally.

            – Mark Barinstein
            Mar 22 at 5:56















          0














          Example:



          create table test (id int not null primary key, a int)@
          create table test_mqt (cnt) as (select sum(a) from test) data initially deferred refresh deferred maintained by user@

          insert into test values (1, 1), (2, 1), (3, 1) with nc@

          create or replace trigger test_aus
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          if (exists (select 1 from n,o where n.id=o.id and n.a<>o.a)) then
          refresh table test_mqt;
          end if;
          end@

          -- trigger IS NOT fired after the following update
          update test set a=1 with nc@
          -- the following select returns 0
          select cnt from test_mqt@

          -- trigger IS fired after the following update
          update test set a=2 with nc@
          -- the following select returns 6
          select cnt from test_mqt@





          share|improve this answer























          • Okay, so the references to OLD TABLE and NEW TABLE represent a single row at a time, but will always loop through each affected row without explicit iterative structures?

            – d.lanza38
            Mar 21 at 20:25











          • n and o here are the correlation names for the transition tables (new and old sets of affected rows), not individual affected rows. "Loop through each affected row" is made by the SQL select statement in the trigger definition.

            – Mark Barinstein
            Mar 21 at 20:29












          • I don't think having the trigger run a refresh makes sense...see my answer for an alternative.

            – Charles
            Mar 21 at 23:03











          • @Charles My example was essentially on how to detect table changes with a for each statement trigger and run some statement, if they are detected. As for real MQT maintenance with triggers - it may be more complex solution. Obviously, we need after insert and after delete triggers and rewritten after update trigger as well, if we don’t use full refresh at some point, and want to maintain our MQT incrementally.

            – Mark Barinstein
            Mar 22 at 5:56













          0












          0








          0







          Example:



          create table test (id int not null primary key, a int)@
          create table test_mqt (cnt) as (select sum(a) from test) data initially deferred refresh deferred maintained by user@

          insert into test values (1, 1), (2, 1), (3, 1) with nc@

          create or replace trigger test_aus
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          if (exists (select 1 from n,o where n.id=o.id and n.a<>o.a)) then
          refresh table test_mqt;
          end if;
          end@

          -- trigger IS NOT fired after the following update
          update test set a=1 with nc@
          -- the following select returns 0
          select cnt from test_mqt@

          -- trigger IS fired after the following update
          update test set a=2 with nc@
          -- the following select returns 6
          select cnt from test_mqt@





          share|improve this answer













          Example:



          create table test (id int not null primary key, a int)@
          create table test_mqt (cnt) as (select sum(a) from test) data initially deferred refresh deferred maintained by user@

          insert into test values (1, 1), (2, 1), (3, 1) with nc@

          create or replace trigger test_aus
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          if (exists (select 1 from n,o where n.id=o.id and n.a<>o.a)) then
          refresh table test_mqt;
          end if;
          end@

          -- trigger IS NOT fired after the following update
          update test set a=1 with nc@
          -- the following select returns 0
          select cnt from test_mqt@

          -- trigger IS fired after the following update
          update test set a=2 with nc@
          -- the following select returns 6
          select cnt from test_mqt@






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Mar 21 at 20:19









          Mark BarinsteinMark Barinstein

          2,329228




          2,329228












          • Okay, so the references to OLD TABLE and NEW TABLE represent a single row at a time, but will always loop through each affected row without explicit iterative structures?

            – d.lanza38
            Mar 21 at 20:25











          • n and o here are the correlation names for the transition tables (new and old sets of affected rows), not individual affected rows. "Loop through each affected row" is made by the SQL select statement in the trigger definition.

            – Mark Barinstein
            Mar 21 at 20:29












          • I don't think having the trigger run a refresh makes sense...see my answer for an alternative.

            – Charles
            Mar 21 at 23:03











          • @Charles My example was essentially on how to detect table changes with a for each statement trigger and run some statement, if they are detected. As for real MQT maintenance with triggers - it may be more complex solution. Obviously, we need after insert and after delete triggers and rewritten after update trigger as well, if we don’t use full refresh at some point, and want to maintain our MQT incrementally.

            – Mark Barinstein
            Mar 22 at 5:56

















          • Okay, so the references to OLD TABLE and NEW TABLE represent a single row at a time, but will always loop through each affected row without explicit iterative structures?

            – d.lanza38
            Mar 21 at 20:25











          • n and o here are the correlation names for the transition tables (new and old sets of affected rows), not individual affected rows. "Loop through each affected row" is made by the SQL select statement in the trigger definition.

            – Mark Barinstein
            Mar 21 at 20:29












          • I don't think having the trigger run a refresh makes sense...see my answer for an alternative.

            – Charles
            Mar 21 at 23:03











          • @Charles My example was essentially on how to detect table changes with a for each statement trigger and run some statement, if they are detected. As for real MQT maintenance with triggers - it may be more complex solution. Obviously, we need after insert and after delete triggers and rewritten after update trigger as well, if we don’t use full refresh at some point, and want to maintain our MQT incrementally.

            – Mark Barinstein
            Mar 22 at 5:56
















          Okay, so the references to OLD TABLE and NEW TABLE represent a single row at a time, but will always loop through each affected row without explicit iterative structures?

          – d.lanza38
          Mar 21 at 20:25





          Okay, so the references to OLD TABLE and NEW TABLE represent a single row at a time, but will always loop through each affected row without explicit iterative structures?

          – d.lanza38
          Mar 21 at 20:25













          n and o here are the correlation names for the transition tables (new and old sets of affected rows), not individual affected rows. "Loop through each affected row" is made by the SQL select statement in the trigger definition.

          – Mark Barinstein
          Mar 21 at 20:29






          n and o here are the correlation names for the transition tables (new and old sets of affected rows), not individual affected rows. "Loop through each affected row" is made by the SQL select statement in the trigger definition.

          – Mark Barinstein
          Mar 21 at 20:29














          I don't think having the trigger run a refresh makes sense...see my answer for an alternative.

          – Charles
          Mar 21 at 23:03





          I don't think having the trigger run a refresh makes sense...see my answer for an alternative.

          – Charles
          Mar 21 at 23:03













          @Charles My example was essentially on how to detect table changes with a for each statement trigger and run some statement, if they are detected. As for real MQT maintenance with triggers - it may be more complex solution. Obviously, we need after insert and after delete triggers and rewritten after update trigger as well, if we don’t use full refresh at some point, and want to maintain our MQT incrementally.

          – Mark Barinstein
          Mar 22 at 5:56





          @Charles My example was essentially on how to detect table changes with a for each statement trigger and run some statement, if they are detected. As for real MQT maintenance with triggers - it may be more complex solution. Obviously, we need after insert and after delete triggers and rewritten after update trigger as well, if we don’t use full refresh at some point, and want to maintain our MQT incrementally.

          – Mark Barinstein
          Mar 22 at 5:56













          1














          Yes, the documentation is here. However, depending on how you are trying to do this, there are some differences between the IBM i command ADDPFTRG and the SQL CREATE TRIGGER.



          ADDPFTRG does not appear to support statement level triggers but CREATE TRIGGER does.



          When using the statement level trigger, you can reference the affected rows with



          REFERENCING OLD TABLE AS ___
          NEW TABLE AS ___


          You can process the old and new table references with SQL statements just as if they were regular tables.



          Just to be clear, OLD TABLE references affected rows as they were before the SQL statement ran, and NEW TABLE references affected rows as they will be after the SQL statment completes.






          share|improve this answer

























          • Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm using FOR EACH STATEMENT as opposed to FOR EACH ROW, how do I still iterate through each affected row so I can compare the before and after values?

            – d.lanza38
            Mar 21 at 20:03











          • Thank you for trying to clarify. But I'm not sure I understand how to iterate through each row. Would I open a cursor based on the aliases I created in the definition? So a cursor on T1 if it were defined as REFERENCING OLD TABLE AS T1...?

            – d.lanza38
            Mar 21 at 20:21











          • Don't think about it as iterating through. Think in sets. Join them together and select the set of rows with differences. If any differences are returned, you would update your MQT, if the set comes back empty, then don't update the MQT.

            – jmarkmurphy
            Mar 21 at 20:25











          • However, you could still be refreshing that MQT a lot. It seems that if you want to keep things in sync, an MQT may not be the way to go, but rather a view or a table function.

            – jmarkmurphy
            Mar 21 at 20:27











          • Okay, so both OLD TABLE and NEW TABLE share the same structure as the table in question, but only contain the affected records and nothing else. I think I got it now. I was thinking those references represented the entire table, not just the rows which were affected.

            – d.lanza38
            Mar 21 at 20:28















          1














          Yes, the documentation is here. However, depending on how you are trying to do this, there are some differences between the IBM i command ADDPFTRG and the SQL CREATE TRIGGER.



          ADDPFTRG does not appear to support statement level triggers but CREATE TRIGGER does.



          When using the statement level trigger, you can reference the affected rows with



          REFERENCING OLD TABLE AS ___
          NEW TABLE AS ___


          You can process the old and new table references with SQL statements just as if they were regular tables.



          Just to be clear, OLD TABLE references affected rows as they were before the SQL statement ran, and NEW TABLE references affected rows as they will be after the SQL statment completes.






          share|improve this answer

























          • Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm using FOR EACH STATEMENT as opposed to FOR EACH ROW, how do I still iterate through each affected row so I can compare the before and after values?

            – d.lanza38
            Mar 21 at 20:03











          • Thank you for trying to clarify. But I'm not sure I understand how to iterate through each row. Would I open a cursor based on the aliases I created in the definition? So a cursor on T1 if it were defined as REFERENCING OLD TABLE AS T1...?

            – d.lanza38
            Mar 21 at 20:21











          • Don't think about it as iterating through. Think in sets. Join them together and select the set of rows with differences. If any differences are returned, you would update your MQT, if the set comes back empty, then don't update the MQT.

            – jmarkmurphy
            Mar 21 at 20:25











          • However, you could still be refreshing that MQT a lot. It seems that if you want to keep things in sync, an MQT may not be the way to go, but rather a view or a table function.

            – jmarkmurphy
            Mar 21 at 20:27











          • Okay, so both OLD TABLE and NEW TABLE share the same structure as the table in question, but only contain the affected records and nothing else. I think I got it now. I was thinking those references represented the entire table, not just the rows which were affected.

            – d.lanza38
            Mar 21 at 20:28













          1












          1








          1







          Yes, the documentation is here. However, depending on how you are trying to do this, there are some differences between the IBM i command ADDPFTRG and the SQL CREATE TRIGGER.



          ADDPFTRG does not appear to support statement level triggers but CREATE TRIGGER does.



          When using the statement level trigger, you can reference the affected rows with



          REFERENCING OLD TABLE AS ___
          NEW TABLE AS ___


          You can process the old and new table references with SQL statements just as if they were regular tables.



          Just to be clear, OLD TABLE references affected rows as they were before the SQL statement ran, and NEW TABLE references affected rows as they will be after the SQL statment completes.






          share|improve this answer















          Yes, the documentation is here. However, depending on how you are trying to do this, there are some differences between the IBM i command ADDPFTRG and the SQL CREATE TRIGGER.



          ADDPFTRG does not appear to support statement level triggers but CREATE TRIGGER does.



          When using the statement level trigger, you can reference the affected rows with



          REFERENCING OLD TABLE AS ___
          NEW TABLE AS ___


          You can process the old and new table references with SQL statements just as if they were regular tables.



          Just to be clear, OLD TABLE references affected rows as they were before the SQL statement ran, and NEW TABLE references affected rows as they will be after the SQL statment completes.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Mar 21 at 20:15

























          answered Mar 21 at 19:52









          jmarkmurphyjmarkmurphy

          8,0902141




          8,0902141












          • Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm using FOR EACH STATEMENT as opposed to FOR EACH ROW, how do I still iterate through each affected row so I can compare the before and after values?

            – d.lanza38
            Mar 21 at 20:03











          • Thank you for trying to clarify. But I'm not sure I understand how to iterate through each row. Would I open a cursor based on the aliases I created in the definition? So a cursor on T1 if it were defined as REFERENCING OLD TABLE AS T1...?

            – d.lanza38
            Mar 21 at 20:21











          • Don't think about it as iterating through. Think in sets. Join them together and select the set of rows with differences. If any differences are returned, you would update your MQT, if the set comes back empty, then don't update the MQT.

            – jmarkmurphy
            Mar 21 at 20:25











          • However, you could still be refreshing that MQT a lot. It seems that if you want to keep things in sync, an MQT may not be the way to go, but rather a view or a table function.

            – jmarkmurphy
            Mar 21 at 20:27











          • Okay, so both OLD TABLE and NEW TABLE share the same structure as the table in question, but only contain the affected records and nothing else. I think I got it now. I was thinking those references represented the entire table, not just the rows which were affected.

            – d.lanza38
            Mar 21 at 20:28

















          • Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm using FOR EACH STATEMENT as opposed to FOR EACH ROW, how do I still iterate through each affected row so I can compare the before and after values?

            – d.lanza38
            Mar 21 at 20:03











          • Thank you for trying to clarify. But I'm not sure I understand how to iterate through each row. Would I open a cursor based on the aliases I created in the definition? So a cursor on T1 if it were defined as REFERENCING OLD TABLE AS T1...?

            – d.lanza38
            Mar 21 at 20:21











          • Don't think about it as iterating through. Think in sets. Join them together and select the set of rows with differences. If any differences are returned, you would update your MQT, if the set comes back empty, then don't update the MQT.

            – jmarkmurphy
            Mar 21 at 20:25











          • However, you could still be refreshing that MQT a lot. It seems that if you want to keep things in sync, an MQT may not be the way to go, but rather a view or a table function.

            – jmarkmurphy
            Mar 21 at 20:27











          • Okay, so both OLD TABLE and NEW TABLE share the same structure as the table in question, but only contain the affected records and nothing else. I think I got it now. I was thinking those references represented the entire table, not just the rows which were affected.

            – d.lanza38
            Mar 21 at 20:28
















          Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm using FOR EACH STATEMENT as opposed to FOR EACH ROW, how do I still iterate through each affected row so I can compare the before and after values?

          – d.lanza38
          Mar 21 at 20:03





          Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm using FOR EACH STATEMENT as opposed to FOR EACH ROW, how do I still iterate through each affected row so I can compare the before and after values?

          – d.lanza38
          Mar 21 at 20:03













          Thank you for trying to clarify. But I'm not sure I understand how to iterate through each row. Would I open a cursor based on the aliases I created in the definition? So a cursor on T1 if it were defined as REFERENCING OLD TABLE AS T1...?

          – d.lanza38
          Mar 21 at 20:21





          Thank you for trying to clarify. But I'm not sure I understand how to iterate through each row. Would I open a cursor based on the aliases I created in the definition? So a cursor on T1 if it were defined as REFERENCING OLD TABLE AS T1...?

          – d.lanza38
          Mar 21 at 20:21













          Don't think about it as iterating through. Think in sets. Join them together and select the set of rows with differences. If any differences are returned, you would update your MQT, if the set comes back empty, then don't update the MQT.

          – jmarkmurphy
          Mar 21 at 20:25





          Don't think about it as iterating through. Think in sets. Join them together and select the set of rows with differences. If any differences are returned, you would update your MQT, if the set comes back empty, then don't update the MQT.

          – jmarkmurphy
          Mar 21 at 20:25













          However, you could still be refreshing that MQT a lot. It seems that if you want to keep things in sync, an MQT may not be the way to go, but rather a view or a table function.

          – jmarkmurphy
          Mar 21 at 20:27





          However, you could still be refreshing that MQT a lot. It seems that if you want to keep things in sync, an MQT may not be the way to go, but rather a view or a table function.

          – jmarkmurphy
          Mar 21 at 20:27













          Okay, so both OLD TABLE and NEW TABLE share the same structure as the table in question, but only contain the affected records and nothing else. I think I got it now. I was thinking those references represented the entire table, not just the rows which were affected.

          – d.lanza38
          Mar 21 at 20:28





          Okay, so both OLD TABLE and NEW TABLE share the same structure as the table in question, but only contain the affected records and nothing else. I think I got it now. I was thinking those references represented the entire table, not just the rows which were affected.

          – d.lanza38
          Mar 21 at 20:28











          0














          I don't think it makes sense to have a trigger run the refresh...



          The whole point of the trigger + MQT would be to have the trigger directly update the MQT table. That way you only have to deal with the exact rows that have changed; rather than force the DB to read the entire base table again.



          create or replace trigger test_aus 
          after update on test
          referencing
          new row as n
          old row as o
          for each row
          mode db2sql
          begin atomic
          if n.a <> o.a then
          update test_mqt set cnt = cnt + n.a - o.a;
          end if;
          end@


          But note that if a change in a is all you are interested in, then you could define the trigger as



          after update of a on test 
          for each row


          that way the trigger will only fire if a is actually updated.



          If you've got more SQL set at a time updates being done than RPG (or SQL) single row updates, then maybe a statement trigger would be worthwhile...



          Something like so:



          create or replace trigger test_aus 
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          update test_mqt
          set cnt = cnt + (select sum(n.a - o.a)
          from N join O using(id)
          where n.a <> o.a
          );

          end@


          Edit: Alternative to MQT

          I've never actually used an MQT in production, since the IBM i doesn't support system maintained MQTs.



          In the scenario where you're interested in an updated aggregate, Encoded Vector Indexes (EVI) with included aggregates may provide a better solution; as they are maintained automatically.



          CREATE ENCODED VECTOR INDEX sales_fact_location_id_evi 
          ON sales_fact(sale_location_id ASC)
          INCLUDE(SUM(sale_amount_measure))


          The example above is from the article Accelerated analytics - faster aggregations using the IBM DB2 for i encoded vector index (EVI) technology . It a good article and compares EVI to MQT for storing aggregates.






          share|improve this answer

























          • As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t have refresh immediate or refresh deferred with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we need after insert and after delete triggers as well. But when things go slightly more complex, such a trigger logic may become too complex very soon, and we finally may decide to end up with a solution like firing full refresh at some point.

            – Mark Barinstein
            Mar 22 at 6:19











          • @MarkBarinstein agree that it is unfortunate that Db2 for i doesn't support system maintained MQT. But if you need real-time updates to MQT, then triggers updating the MQT are the only option. If real-time isn't needed, then a scheduled refresh (with either the refresh statement or a user program) is ok. Having a trigger use the refresh command doesn't make sense.

            – Charles
            Mar 22 at 15:58















          0














          I don't think it makes sense to have a trigger run the refresh...



          The whole point of the trigger + MQT would be to have the trigger directly update the MQT table. That way you only have to deal with the exact rows that have changed; rather than force the DB to read the entire base table again.



          create or replace trigger test_aus 
          after update on test
          referencing
          new row as n
          old row as o
          for each row
          mode db2sql
          begin atomic
          if n.a <> o.a then
          update test_mqt set cnt = cnt + n.a - o.a;
          end if;
          end@


          But note that if a change in a is all you are interested in, then you could define the trigger as



          after update of a on test 
          for each row


          that way the trigger will only fire if a is actually updated.



          If you've got more SQL set at a time updates being done than RPG (or SQL) single row updates, then maybe a statement trigger would be worthwhile...



          Something like so:



          create or replace trigger test_aus 
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          update test_mqt
          set cnt = cnt + (select sum(n.a - o.a)
          from N join O using(id)
          where n.a <> o.a
          );

          end@


          Edit: Alternative to MQT

          I've never actually used an MQT in production, since the IBM i doesn't support system maintained MQTs.



          In the scenario where you're interested in an updated aggregate, Encoded Vector Indexes (EVI) with included aggregates may provide a better solution; as they are maintained automatically.



          CREATE ENCODED VECTOR INDEX sales_fact_location_id_evi 
          ON sales_fact(sale_location_id ASC)
          INCLUDE(SUM(sale_amount_measure))


          The example above is from the article Accelerated analytics - faster aggregations using the IBM DB2 for i encoded vector index (EVI) technology . It a good article and compares EVI to MQT for storing aggregates.






          share|improve this answer

























          • As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t have refresh immediate or refresh deferred with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we need after insert and after delete triggers as well. But when things go slightly more complex, such a trigger logic may become too complex very soon, and we finally may decide to end up with a solution like firing full refresh at some point.

            – Mark Barinstein
            Mar 22 at 6:19











          • @MarkBarinstein agree that it is unfortunate that Db2 for i doesn't support system maintained MQT. But if you need real-time updates to MQT, then triggers updating the MQT are the only option. If real-time isn't needed, then a scheduled refresh (with either the refresh statement or a user program) is ok. Having a trigger use the refresh command doesn't make sense.

            – Charles
            Mar 22 at 15:58













          0












          0








          0







          I don't think it makes sense to have a trigger run the refresh...



          The whole point of the trigger + MQT would be to have the trigger directly update the MQT table. That way you only have to deal with the exact rows that have changed; rather than force the DB to read the entire base table again.



          create or replace trigger test_aus 
          after update on test
          referencing
          new row as n
          old row as o
          for each row
          mode db2sql
          begin atomic
          if n.a <> o.a then
          update test_mqt set cnt = cnt + n.a - o.a;
          end if;
          end@


          But note that if a change in a is all you are interested in, then you could define the trigger as



          after update of a on test 
          for each row


          that way the trigger will only fire if a is actually updated.



          If you've got more SQL set at a time updates being done than RPG (or SQL) single row updates, then maybe a statement trigger would be worthwhile...



          Something like so:



          create or replace trigger test_aus 
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          update test_mqt
          set cnt = cnt + (select sum(n.a - o.a)
          from N join O using(id)
          where n.a <> o.a
          );

          end@


          Edit: Alternative to MQT

          I've never actually used an MQT in production, since the IBM i doesn't support system maintained MQTs.



          In the scenario where you're interested in an updated aggregate, Encoded Vector Indexes (EVI) with included aggregates may provide a better solution; as they are maintained automatically.



          CREATE ENCODED VECTOR INDEX sales_fact_location_id_evi 
          ON sales_fact(sale_location_id ASC)
          INCLUDE(SUM(sale_amount_measure))


          The example above is from the article Accelerated analytics - faster aggregations using the IBM DB2 for i encoded vector index (EVI) technology . It a good article and compares EVI to MQT for storing aggregates.






          share|improve this answer















          I don't think it makes sense to have a trigger run the refresh...



          The whole point of the trigger + MQT would be to have the trigger directly update the MQT table. That way you only have to deal with the exact rows that have changed; rather than force the DB to read the entire base table again.



          create or replace trigger test_aus 
          after update on test
          referencing
          new row as n
          old row as o
          for each row
          mode db2sql
          begin atomic
          if n.a <> o.a then
          update test_mqt set cnt = cnt + n.a - o.a;
          end if;
          end@


          But note that if a change in a is all you are interested in, then you could define the trigger as



          after update of a on test 
          for each row


          that way the trigger will only fire if a is actually updated.



          If you've got more SQL set at a time updates being done than RPG (or SQL) single row updates, then maybe a statement trigger would be worthwhile...



          Something like so:



          create or replace trigger test_aus 
          after update on test
          referencing
          new table as n
          old table as o
          for each statement
          mode db2sql
          begin atomic
          update test_mqt
          set cnt = cnt + (select sum(n.a - o.a)
          from N join O using(id)
          where n.a <> o.a
          );

          end@


          Edit: Alternative to MQT

          I've never actually used an MQT in production, since the IBM i doesn't support system maintained MQTs.



          In the scenario where you're interested in an updated aggregate, Encoded Vector Indexes (EVI) with included aggregates may provide a better solution; as they are maintained automatically.



          CREATE ENCODED VECTOR INDEX sales_fact_location_id_evi 
          ON sales_fact(sale_location_id ASC)
          INCLUDE(SUM(sale_amount_measure))


          The example above is from the article Accelerated analytics - faster aggregations using the IBM DB2 for i encoded vector index (EVI) technology . It a good article and compares EVI to MQT for storing aggregates.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Mar 22 at 16:06

























          answered Mar 21 at 21:01









          CharlesCharles

          11.4k11132




          11.4k11132












          • As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t have refresh immediate or refresh deferred with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we need after insert and after delete triggers as well. But when things go slightly more complex, such a trigger logic may become too complex very soon, and we finally may decide to end up with a solution like firing full refresh at some point.

            – Mark Barinstein
            Mar 22 at 6:19











          • @MarkBarinstein agree that it is unfortunate that Db2 for i doesn't support system maintained MQT. But if you need real-time updates to MQT, then triggers updating the MQT are the only option. If real-time isn't needed, then a scheduled refresh (with either the refresh statement or a user program) is ok. Having a trigger use the refresh command doesn't make sense.

            – Charles
            Mar 22 at 15:58

















          • As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t have refresh immediate or refresh deferred with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we need after insert and after delete triggers as well. But when things go slightly more complex, such a trigger logic may become too complex very soon, and we finally may decide to end up with a solution like firing full refresh at some point.

            – Mark Barinstein
            Mar 22 at 6:19











          • @MarkBarinstein agree that it is unfortunate that Db2 for i doesn't support system maintained MQT. But if you need real-time updates to MQT, then triggers updating the MQT are the only option. If real-time isn't needed, then a scheduled refresh (with either the refresh statement or a user program) is ok. Having a trigger use the refresh command doesn't make sense.

            – Charles
            Mar 22 at 15:58
















          As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t have refresh immediate or refresh deferred with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we need after insert and after delete triggers as well. But when things go slightly more complex, such a trigger logic may become too complex very soon, and we finally may decide to end up with a solution like firing full refresh at some point.

          – Mark Barinstein
          Mar 22 at 6:19





          As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t have refresh immediate or refresh deferred with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we need after insert and after delete triggers as well. But when things go slightly more complex, such a trigger logic may become too complex very soon, and we finally may decide to end up with a solution like firing full refresh at some point.

          – Mark Barinstein
          Mar 22 at 6:19













          @MarkBarinstein agree that it is unfortunate that Db2 for i doesn't support system maintained MQT. But if you need real-time updates to MQT, then triggers updating the MQT are the only option. If real-time isn't needed, then a scheduled refresh (with either the refresh statement or a user program) is ok. Having a trigger use the refresh command doesn't make sense.

          – Charles
          Mar 22 at 15:58





          @MarkBarinstein agree that it is unfortunate that Db2 for i doesn't support system maintained MQT. But if you need real-time updates to MQT, then triggers updating the MQT are the only option. If real-time isn't needed, then a scheduled refresh (with either the refresh statement or a user program) is ok. Having a trigger use the refresh command doesn't make sense.

          – Charles
          Mar 22 at 15:58

















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55287128%2fdb2-for-i-triggers-once-per-statement-but-comparing-before-and-after-values%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

          Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

          Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript