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;
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
add a comment |
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
add a comment |
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
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
db2 database-trigger db2-400 materialized-views
asked Mar 21 at 18:36
d.lanza38d.lanza38
96251636
96251636
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
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@
Okay, so the references toOLD TABLE
andNEW 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
ando
here are the correlation names for the transitiontables
(new and old sets of affected rows), not individual affectedrows
. "Loop through each affected row" is made by the SQLselect
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 afor 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 needafter insert
andafter delete
triggers and rewrittenafter 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
add a comment |
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.
Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm usingFOR EACH STATEMENT
as opposed toFOR 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 onT1
if it were defined asREFERENCING 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 bothOLD TABLE
andNEW 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
add a comment |
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.
As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t haverefresh immediate
orrefresh deferred
with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we needafter insert
andafter 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
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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@
Okay, so the references toOLD TABLE
andNEW 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
ando
here are the correlation names for the transitiontables
(new and old sets of affected rows), not individual affectedrows
. "Loop through each affected row" is made by the SQLselect
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 afor 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 needafter insert
andafter delete
triggers and rewrittenafter 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
add a comment |
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@
Okay, so the references toOLD TABLE
andNEW 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
ando
here are the correlation names for the transitiontables
(new and old sets of affected rows), not individual affectedrows
. "Loop through each affected row" is made by the SQLselect
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 afor 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 needafter insert
andafter delete
triggers and rewrittenafter 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
add a comment |
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@
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@
answered Mar 21 at 20:19
Mark BarinsteinMark Barinstein
2,329228
2,329228
Okay, so the references toOLD TABLE
andNEW 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
ando
here are the correlation names for the transitiontables
(new and old sets of affected rows), not individual affectedrows
. "Loop through each affected row" is made by the SQLselect
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 afor 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 needafter insert
andafter delete
triggers and rewrittenafter 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
add a comment |
Okay, so the references toOLD TABLE
andNEW 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
ando
here are the correlation names for the transitiontables
(new and old sets of affected rows), not individual affectedrows
. "Loop through each affected row" is made by the SQLselect
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 afor 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 needafter insert
andafter delete
triggers and rewrittenafter 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
add a comment |
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.
Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm usingFOR EACH STATEMENT
as opposed toFOR 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 onT1
if it were defined asREFERENCING 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 bothOLD TABLE
andNEW 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
add a comment |
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.
Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm usingFOR EACH STATEMENT
as opposed toFOR 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 onT1
if it were defined asREFERENCING 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 bothOLD TABLE
andNEW 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
add a comment |
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.
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.
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 usingFOR EACH STATEMENT
as opposed toFOR 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 onT1
if it were defined asREFERENCING 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 bothOLD TABLE
andNEW 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
add a comment |
Thank you @jmarkmurphy. So I've read through that documentation already, but what I didn't find intuitive is if I'm usingFOR EACH STATEMENT
as opposed toFOR 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 onT1
if it were defined asREFERENCING 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 bothOLD TABLE
andNEW 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
add a comment |
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.
As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t haverefresh immediate
orrefresh deferred
with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we needafter insert
andafter 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
add a comment |
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.
As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t haverefresh immediate
orrefresh deferred
with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we needafter insert
andafter 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
add a comment |
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.
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.
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 haverefresh immediate
orrefresh deferred
with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we needafter insert
andafter 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
add a comment |
As for real MQT mantenance with triggers. Unfortunately, DB2 for IBM i still doesn’t haverefresh immediate
orrefresh deferred
with incremental maintenance MQTs as, for example, Db2 for LUW does. Because of this even for such a simplest case we needafter insert
andafter 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
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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