0

In Interbase 2009 db I have master and detail tables(Tmaster, Tdetails).

Tmaster:

master_id(pk) DocSumma DocSummaDol

Tdetails:

det_id master_id(fk) price1,price2 qnt

After I delete/update records in child table(Tdetails) procedure must update summa in master table(Tmaster).

I have 2 problems:

  1. If procedure contains this if-clause:
if (m.DocSumma=0) then begin delete from Tmaster m where m.master_id=:master_id; end

it returns this error:

Column does not belong to referenced table. Dynamic SQL Error. SQL error code = -206. Column unknown.

  1. Without if-clause I have the second problem: procedure works very slow. It would be end after 13hrs :)

Sometimes in IBExpert I get this error:

Arithmetic overflow or division by zero has occurred. arithmetic exception, numeric overflow, or string truncation. SQLCODE: -802 GDSCODE: 335544321

what is wrong in my Psql code?

alter procedure sp_recalculate_summa
as
    declare variable master_id integer;
    declare variable det_id integer;
    declare variable sum1 decimal(8,4) ;
    declare variable sum2 decimal(8,4) ;
    begin
        for  select m.master_id
        from Tmaster m
        into :master_id
        do begin
            sum1=0;
            sum2=0;
            for select det_id,
                      sum(d.price1*d.qnt)as summa1,
                      sum(d.price2*d.qnt)as summa2
            from Tdetails d, Tmaster m
            where d.det_id=:master_id
            group by det_id
            into :det_id,:sum1,:sum2
            do
                if (m.DocSumma=0) then begin 
                    delete from Tmaster m where m.master_id=:master_id; 
                end 
                Else begin
                    update Tmaster set DocSumma=:sum1 where master_id=:master_id;
                    update Tmaster set DocSummaDol=:sum2 where master_id=:master_id;
                end
        end
    end
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
basti
  • 399
  • 2
  • 10
  • This smacks a little of poor design - your master table shouldn't be dependant on your child table updating it. Perhaps a view would be more appropriate that compounds your master and child tables to produce the values you're looking for? – Paul Jan 14 '21 at 09:29
  • @Paul Master table isn't dependent on child table. This app has been working for more than one year. – basti Jan 14 '21 at 09:43
  • Could you also provide the DDL for the tables involved? Out of curiosity: why isn't this handled through a trigger on `tdetails`? – Mark Rotteveel Jan 14 '21 at 10:12
  • Could you also explain why this question is tagged with firebird, interbase and interbase-2009? Firebird and InterBase, despite their common ancestry are not the same thing. – Mark Rotteveel Jan 14 '21 at 10:24
  • Mark Rotteveel, I know that there is no link with Firebird but I attempt to attract attention from their side as well as they FB and IB common ancestry and adult programmers know both IB and FB :) – basti Jan 14 '21 at 11:43
  • "why isn't this handled through a trigger on tdetails?" Mark Rotteveel, this sp must work only once. I delete records from detail table and want to recalculate summa in master table. So I want run it from other program on button click. – basti Jan 14 '21 at 12:28

1 Answers1

1

The problem is not with the delete statement, the problem is with if (m.DocSumma=0) then begin. You cannot refer to a table like that inside a PSQL block. You need to explicitly assign that column value to a local variable.

For example, something like:

alter procedure sp_recalculate_summa
as
    declare variable master_id integer;
    declare variable DocSumma decimal(8,4);
    declare variable det_id integer;
    declare variable sum1 decimal(8,4) ;
    declare variable sum2 decimal(8,4) ;
    begin
        for  select m.master_id, m.DocSumma
        from Tmaster m
        into master_id, DocSumma
        do begin
            sum1=0;
            sum2=0;
            for select det_id,
                      sum(d.price1*d.qnt)as summa1,
                      sum(d.price2*d.qnt)as summa2
            from Tdetails d, Tmaster m
            where d.det_id=:master_id
            group by det_id
            into det_id,sum1,sum2
            do
                if (DocSumma=0) then begin 
                -- etc..
                end
        end
    end

As additional remarks:

  • I question the correctness of the condition if (m.DocSumma=0) then begin (if (DocSumma=0) then begin in my proposed change), shouldn't this be if (sum1 = 0) then begin? As in, it should use the updated sum, instead of the old sum.

  • Also, why are you updating TMASTER twice? It would be more efficient to use a single update:

    update Tmaster set DocSumma=:sum1, DocSummaDol=:sum2 where master_id=:master_id;
    
  • Some of these changes might better be done through triggers on TDETAILS and maybe TMASTER, instead of using a delayed explicit recalculation.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • Mark Rotteveel, I created variable "DocSumma" but it was insufficient for disappear error message . After that I change from-clause in detail select statement "from Tdetails d, Tmaster m" with "from Tdetails d" it works properly, without error message but it is slow. For example, it will be modify 150 000 records in more than 75 mins. Other procedures in db work fast. Indexes for m.master_id, m.DocSumma, d.det_id are created. :( – basti Jan 14 '21 at 13:48
  • @basti I hadn't looked deeper, but doing `from Tdetails d, Tmaster m` also doesn't make a lot of sense: that is a cross join, for each row in `TDETAILS`, it will join all records of `TMASTER`. Maybe you intended to do an inner join instead. – Mark Rotteveel Jan 14 '21 at 14:18
  • @basti In any case, the code as shown in my answer compiles fine on Firebird. I guess that you didn't apply the change exactly as in my answer. – Mark Rotteveel Jan 14 '21 at 14:27
  • Mark Rotteveel, I rollbacked only this change (add in where-clause 'Tmaster' and error message appeared again. I don't know why this happens. If I not add DocSumma variable it wouldn't be work. Now sp works fine but it's very slow. :( p.s. Out of curiosity, which application you use for complie without real db in? – basti Jan 14 '21 at 14:52
  • @basti I used Firebird, I replicated your table structure (guessing at the column types), and then created the procedure with the code in my answer. So, I used a 'real' database. With that out of my way, your comments are not really clear as to what problem(s) you still have. – Mark Rotteveel Jan 14 '21 at 14:55
  • Mark Rotteveel, now it works fine, without error but is very slow. I thought maybe exists other reasons in procedure or etc why sp works so slow. There are about 150 000 records in my test db and sp would be end work after about 75 min. In the real db it would be 13hrs :( – basti Jan 14 '21 at 15:03
  • @basti Did you remove the incorrect cross join from the nested query? Have you considered changing this so you only execute a single query, instead of N + 1 queries? – Mark Rotteveel Jan 14 '21 at 15:04
  • Mark Rotteveel, yes. I remove old sp, compile new and then restart server. After that I reopen IBExpert. Sp code is renewed but... :( – basti Jan 14 '21 at 15:07
  • Mark Rotteveel, If I execute sp 2-3 times error message appeared again. :( – basti Jan 14 '21 at 15:11
  • @basti That is far too vague to be able to answer. Consider asking a new question and include all relevant details. – Mark Rotteveel Jan 14 '21 at 15:13