Khairul Fathi
Khairul Fathi

Reputation: 23

Self reference update on insert trigger in Informix

I'm extracting data from various sources into one table. In this new table, there's a field called lineno. This field value is should be in sequence based on company code and batch number. I've wrote the following procedure

CREATE PROCEDURE update_line(company CHAR(4), batch CHAR(8), rcptid CHAR(12));

DEFINE lineno INT;

SELECT Count(*) 
INTO lineno
FROM tmp_cb_rcpthdr
WHERE cbrh_company = company
AND cbrh_batchid = batch;

UPDATE tmp_cb_rcpthdr
SET cbrh_lineno = lineno + 1
WHERE cbrh_company = company
AND cbrh_batchid = batch
AND cbrh_rcptid = rcptid;

END PROCEDURE;

This procedure will be called using the following trigger

CREATE TRIGGER tmp_cb_rcpthdr_ins INSERT ON tmp_cb_rcpthdr 
REFERENCING NEW AS n
FOR EACH ROW
(
    EXECUTE PROCEDURE update_line(n.company, cbrh_batchid, cbrh_rcptid)
);

However, I got the following error

SQL Error = -747 Table or column matches object referenced in triggering statement.

From oninit.com, I learn that the error caused by a triggered SQL statement acts on the triggering table which in this case is the UPDATE statement. So my question is, how do I solve this problem? Is there any work around or better solution?

Upvotes: 2

Views: 4365

Answers (1)

RET
RET

Reputation: 9188

I think the design needs to be reconsidered. For a start, what happens if some rows get deleted from tmp_cb_rcpthdr ? The COUNT(*) query will result in duplicate lineno values.

Even if this is an ETL only process, and you can be confident the data won't be manipulated from elsewhere, performance will be an issue, and will only get worse the more data you have for any one combination of company and batch_id.

Is it necessary for the lineno to increment from zero, or is it just to maintain the original load order? Because if it's the latter, a SEQUENCE or a SERIAL field on the table will achieve the same end, and be a lot more efficient.

If you must generate lineno in this way, I would suggest you create a second control table, keyed on company and batch_id, that tracks the current lineno value, ie: (untested)

CREATE PROCEDURE update_line(company CHAR(4), batch CHAR(8));

    DEFINE lineno INT;

    SELECT cbrh_lineno INTO lineno 
    FROM linenoctl
    WHERE cbrh_company = company
    AND cbrh_batchid = batch;

    UPDATE linenoctl
    SET cbrh_lineno = lineno + 1
    WHERE cbrh_company = company
    AND cbrh_batchid = batch;
    -- A test that no other process has grabbed this record
    -- might need to be considered here, ie cbrh_lineno = lineno

    RETURN lineno + 1
END PROCEDURE;

Then use it as follows:

CREATE TRIGGER tmp_cb_rcpthdr_ins INSERT ON tmp_cb_rcpthdr 
REFERENCING NEW AS n
FOR EACH ROW
(
    EXECUTE PROCEDURE update_line(n.company, cbrh_batchid) INTO cbrh_lineno
);

See the IDS documentation for more on using calculated values with triggers.

Upvotes: 1

Related Questions