Re: trigger with cascade delete problem

2014-06-16 Thread Tim Dudgeon

On 13/06/2014 13:59, Rick Hillegas wrote:


Maybe
you can share a simplified problem which shows why this aggregation is
so tricky.

Thanks,
-Rick




Hi Rick

Thanks for your patience!
I've tried to create a minimal version that describes the problem:

create table XXX (
XXX_ID int primary key generated always as identity
);

create table GROUPING (
GROUPING_ID int primary key generated always as identity,
XXX_ID INT,
constraint GROUPING2XXX foreign key (XXX_ID) references XXX 
(XXX_ID) on delete cascade

);

create table MAIN (
MAIN_ID INT generated always as identity,
GROUPING_ID INT,
YYY_ID INT,
NAME VARCHAR(50),
constraint MAIN2GROUPING foreign key (GROUPING_ID) references 
GROUPING (GROUPING_ID) on delete cascade

);

create table AGGREGATES (
AGGREGATES_ID int generated always as identity,
XXX_ID INT,
YYY_ID INT,
NAME VARCHAR(50)
);



The key parts is that AGGREGATES contains data that is grouped by YYY_ID 
(from MAIN) and XXX_ID (from XXX/GROUPING).
So when a row from MAIN is deleted its CORRESPONDING row in AGGREGATE 
needs updating, which I'm doing by doing a delete followed by an INSERT.
The row to delete is the one defined by the corresponding YYY_ID and 
XXX_ID values. And to get the corresponding XXX_ID values I need to join 
back to the GROUPING table. But in the case of a cascade delete caused 
by deletion of a row in GROUPING the row I need to join on is no longer 
present, as its just been deleted.


And I can't do a cascade delete from GROUPING to AGGREGATES as that 
would delete all AGGREGATES with the corresponding XXX_ID, not just 
those with the correct XXX_IDs.


I hope this is clearer!

Tim






Re: trigger with cascade delete problem

2014-06-16 Thread Rick Hillegas

On 6/16/14 1:07 AM, Tim Dudgeon wrote:

On 13/06/2014 13:59, Rick Hillegas wrote:


Maybe
you can share a simplified problem which shows why this aggregation is
so tricky.

Thanks,
-Rick




Hi Rick

Thanks for your patience!
I've tried to create a minimal version that describes the problem:

create table XXX (
XXX_ID int primary key generated always as identity
);

create table GROUPING (
GROUPING_ID int primary key generated always as identity,
XXX_ID INT,
constraint GROUPING2XXX foreign key (XXX_ID) references XXX 
(XXX_ID) on delete cascade

);

create table MAIN (
MAIN_ID INT generated always as identity,
GROUPING_ID INT,
YYY_ID INT,
NAME VARCHAR(50),
constraint MAIN2GROUPING foreign key (GROUPING_ID) references 
GROUPING (GROUPING_ID) on delete cascade

);

create table AGGREGATES (
AGGREGATES_ID int generated always as identity,
XXX_ID INT,
YYY_ID INT,
NAME VARCHAR(50)
);



The key parts is that AGGREGATES contains data that is grouped by 
YYY_ID (from MAIN) and XXX_ID (from XXX/GROUPING).
So when a row from MAIN is deleted its CORRESPONDING row in AGGREGATE 
needs updating, which I'm doing by doing a delete followed by an INSERT.
The row to delete is the one defined by the corresponding YYY_ID and 
XXX_ID values. And to get the corresponding XXX_ID values I need to 
join back to the GROUPING table. But in the case of a cascade delete 
caused by deletion of a row in GROUPING the row I need to join on is 
no longer present, as its just been deleted.


And I can't do a cascade delete from GROUPING to AGGREGATES as that 
would delete all AGGREGATES with the corresponding XXX_ID, not just 
those with the correct XXX_IDs.


I hope this is clearer!

Tim






Hi Tim,

I wonder if you could use a BEFORE trigger which buffers some result in 
memory for later use by your AFTER trigger. Something like this:


create procedure PRECOMPUTE( grouping_id int )
language java parameter style java reads sql data
external name 'zz.precompute';

-- precompute the result
CREATE TRIGGER trg_beforedelete1 NO CASCADE BEFORE DELETE ON MAIN
REFERENCING OLD ROW AS OLD  FOR EACH ROW MODE DB2SQL
CALL precompute( OLD.GROUPING_ID );

The deleted rows could even be buffered up in memory by a BEFORE trigger 
and then they could be wrapped by a table function for use in the join 
performed by the AFTER trigger.


Disclaimer: I haven't tried this experiment. I'm just waving my hands.

Hope this helps,
-Rick



Re: trigger with cascade delete problem

2014-06-13 Thread Rick Hillegas

Hi Tim,

I still don't think I understand what's not working. Here's my crude 
understanding:


1) You have 3 tables:

MAIN - This contains the information to be aggregated.

GROUPING - This contains facts needed to group the information in MAIN

AGGREGATES - This contains a pre-computed, grouped aggregation of MAIN, 
using the groups in GROUPING


2) A foreign key from MAIN to GROUPING defines the groups. It's unclear 
whether a similar foreign key links AGGREGATES to GROUPING.


3) When you delete a group from GROUPING, cascade actions delete the 
rows in the group from MAIN. And some triggers bring AGGREGATES back 
into agreement with the facts in MAIN and GROUPING.


I understand why deleting a group means that you need to delete the 
corresponding aggregated result for that group from AGGREGATES. What I 
don't understand is why you need to do anything else to AGGREGATES. Is 
what's in AGGREGATES not simply the result of a grouped aggregation?


I don't think I can speculate further without knowing more about how the 
contents of AGGREGATES are calculated. I understand that this may be the 
special sauce of your application which you don't want to share. Maybe 
you can share a simplified problem which shows why this aggregation is 
so tricky.


Thanks,
-Rick



Re: trigger with cascade delete problem

2014-06-12 Thread Tim Dudgeon
OK, so here's a simplified example. Didn't want to raise a JIRA as I'm 
really not sure this is a bug.


Tim

drop table MAIN;
drop table DELETIONS;
drop table CHANGED;

create table MAIN (
MAIN_ID INT generated always as identity,
GROUPING_ID INT,
NAME VARCHAR(50)
);

create table DELETIONS (
DELETIONS_ID int generated always as identity,
MAIN_ID INT,
NAME VARCHAR(50),
WHENITHAPPENED TIMESTAMP
);

create table CHANGED (
CHANGED_ID INT generated always as identity,
MAIN_ID INT,
NAME VARCHAR(50),
WHENITHAPPENED TIMESTAMP
);

insert into MAIN (GROUPING_ID, NAME) values
(1, 'banana'),
(1, 'lemon'),
(1, 'grapefruit'),
(2, 'apple'),
(2, 'broccoli'),
(3, 'strawberry'),
(3, 'redcurrent'),
(3, 'cherry');

select * from MAIN;

-- this trigger records what has been deleted from MAIN
CREATE TRIGGER trg_delete1 AFTER DELETE ON MAIN
REFERENCING OLD TABLE AS OLD FOR EACH STATEMENT MODE DB2SQL
INSERT into CHANGED (MAIN_ID, NAME, WHENITHAPPENED)
SELECT MAIN_ID, NAME, CURRENT_TIMESTAMP FROM OLD;

-- tries to record all rows with the same GROUPING_ID as any of the 
deleted rows

CREATE TRIGGER trg_delete2 AFTER DELETE ON MAIN
REFERENCING OLD TABLE AS OLD FOR EACH STATEMENT MODE DB2SQL
INSERT into DELETIONS (MAIN_ID, NAME, WHENITHAPPENED)
SELECT MAIN.MAIN_ID, MAIN.NAME, CURRENT_TIMESTAMP FROM MAIN, OLD
WHERE MAIN.GROUPING_ID = OLD.GROUPING_ID;

delete from MAIN where MAIN_ID = 1;
select * from MAIN; -- banana deleted as expected
select * from CHANGED; -- banana present as expected
select * from DELETIONS; -- lemon and grapefruit present as expected, 
but no banana








Re: trigger with cascade delete problem

2014-06-12 Thread Rick Hillegas

On 6/12/14 5:33 AM, Tim Dudgeon wrote:
OK, so here's a simplified example. Didn't want to raise a JIRA as I'm 
really not sure this is a bug.


Tim

drop table MAIN;
drop table DELETIONS;
drop table CHANGED;

create table MAIN (
MAIN_ID INT generated always as identity,
GROUPING_ID INT,
NAME VARCHAR(50)
);

create table DELETIONS (
DELETIONS_ID int generated always as identity,
MAIN_ID INT,
NAME VARCHAR(50),
WHENITHAPPENED TIMESTAMP
);

create table CHANGED (
CHANGED_ID INT generated always as identity,
MAIN_ID INT,
NAME VARCHAR(50),
WHENITHAPPENED TIMESTAMP
);

insert into MAIN (GROUPING_ID, NAME) values
(1, 'banana'),
(1, 'lemon'),
(1, 'grapefruit'),
(2, 'apple'),
(2, 'broccoli'),
(3, 'strawberry'),
(3, 'redcurrent'),
(3, 'cherry');

select * from MAIN;

-- this trigger records what has been deleted from MAIN
CREATE TRIGGER trg_delete1 AFTER DELETE ON MAIN
REFERENCING OLD TABLE AS OLD FOR EACH STATEMENT MODE DB2SQL
INSERT into CHANGED (MAIN_ID, NAME, WHENITHAPPENED)
SELECT MAIN_ID, NAME, CURRENT_TIMESTAMP FROM OLD;

-- tries to record all rows with the same GROUPING_ID as any of the 
deleted rows

CREATE TRIGGER trg_delete2 AFTER DELETE ON MAIN
REFERENCING OLD TABLE AS OLD FOR EACH STATEMENT MODE DB2SQL
INSERT into DELETIONS (MAIN_ID, NAME, WHENITHAPPENED)
SELECT MAIN.MAIN_ID, MAIN.NAME, CURRENT_TIMESTAMP FROM MAIN, OLD
WHERE MAIN.GROUPING_ID = OLD.GROUPING_ID;

delete from MAIN where MAIN_ID = 1;
select * from MAIN; -- banana deleted as expected
select * from CHANGED; -- banana present as expected
select * from DELETIONS; -- lemon and grapefruit present as expected, 
but no banana

Hi Tim,

This result looks correct to me. The trg_delete2 trigger fires AFTER the 
deletion and inside the same transaction. So it sees the state of the 
MAIN table AFTER the banana tuple was deleted. From its perspective, the 
banana table should not appear in the join.


Or did I misunderstand your question?

Hope this helps,
-Rick











Re: trigger with cascade delete problem

2014-06-12 Thread Tim Dudgeon

Hi Rick,

So much as I expected. Its probably not a bug, and working exactly as 
planned.


So my question is how to get the behaviour I want!
I can't use a BEFORE trigger as that doesn't let me delete rows (which 
is my real use case - the example is a gross simplification).
I need to do a join to get the data I need, but the join depends on 
something that has just been deleted because this is an ON DELETE triger.


Tim



Hi Tim,

This result looks correct to me. The trg_delete2 trigger fires AFTER the
deletion and inside the same transaction. So it sees the state of the
MAIN table AFTER the banana tuple was deleted. From its perspective, the
banana table should not appear in the join.

Or did I misunderstand your question?

Hope this helps,
-Rick





Re: trigger with cascade delete problem

2014-06-11 Thread Rick Hillegas

On 6/11/14 2:40 AM, Tim Dudgeon wrote:
I've encountered a tricky problem that I can't see a solution to at 
present. Let me describe.


I have 3 tables:
MAIN - the main data table with results in.
GROUPING - a table that is related to MAIN, with MAIM having a FK 
constraint to GROUPING
AGGREGATES - a table that contains aggregated information from MAIN, 
in part grouped by the info in GROUPING.


I'm filling the data in AGGREGATES using triggers on MAIN that firstly 
delete the old aggregate value and then inserts a new aggregate (e.g. 
2 after insert/update/delete for each statement triggers).


Mostly its working. When I delete a row in MAIN the row in AGGREGATES 
gets deleted and then inserted again with the new aggregate.
But when I delete a row from GROUPING and the cascade delete causes 
the corresponding rows in MAIN to be deleted it does not work.
I'm pretty sure this is because part of the selection criteria for the 
rows to delete involves a join to GROUPING, and the rows to join to 
have just been blown away by the delete operation, so nothing in 
AGGREGATES gets deleted.


Is there solution to this?

Tim



Hi Tim,

I'm sure I don't understand the complexity of your problem. But it 
sounds as though there may be tuples in MAIN with null foreign keys and 
somehow these are involved in the aggregation function. Often the 
solution to a missing join problem is to use a left join rather than 
an inner join.


Hope this helps,
-Rick



Re: trigger with cascade delete problem

2014-06-11 Thread Dag H. Wanvik

Tim,

if you could produce a JIRA with a repro for this scenario, we could 
take a look at the generated code for the query.


Thanks,
Dag

On 11. juni 2014 16:48, Tim Dudgeon wrote:

Hi Tim,

I'm sure I don't understand the complexity of your problem. But it
sounds as though there may be tuples in MAIN with null foreign keys and
somehow these are involved in the aggregation function. Often the
solution to a missing join problem is to use a left join rather than
an inner join.

Hope this helps,
-Rick




No, the data is good. No missing keys. Inner join gets everything.

I *think* its because is a cascade delete,
Should the cascade delete and the firing of the trigger all happen in 
the same transaction and see the deleted row in GROUPING that caused 
the cascasde deltete? It looks like it doesn't


Tim






Re: trigger with cascade delete problem

2014-06-11 Thread Dag H. Wanvik

Tim,

if you could produce a JITA with a repro for this scenario, we could 
take a look at the generated code for the query.


Thanks,
Dag

On 11. juni 2014 16:48, Tim Dudgeon wrote:

Hi Tim,

I'm sure I don't understand the complexity of your problem. But it
sounds as though there may be tuples in MAIN with null foreign keys and
somehow these are involved in the aggregation function. Often the
solution to a missing join problem is to use a left join rather than
an inner join.

Hope this helps,
-Rick




No, the data is good. No missing keys. Inner join gets everything.

I *think* its because is a cascade delete,
Should the cascade delete and the firing of the trigger all happen in 
the same transaction and see the deleted row in GROUPING that caused 
the cascasde deltete? It looks like it doesn't


Tim