Re: Novice PL/pgSQL question and example

From: James Long <pgsql-novice(at)museum(dot)rain(dot)com>
To: pgsql-novice(at)postgresql(dot)org
Subject: Re: Novice PL/pgSQL question and example
Date: 2010-02-08 19:31:29
Message-ID: 20100208193129.GB47010@ns.umpquanet.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-novice

Pardon the edit, but I'll delete the previous quotations, since
the issues of syntax and functionality are resolved. Thank you, Tom.

The next problem is simplicity, or elegance, if you like.

I would like the code to read like this:

CREATE OR REPLACE FUNCTION share_cost( cost NUMERIC ) RETURNS VOID AS $$

-- Spread the amount COST across a number of records WHERE reference = 'SHARE'
-- increment the AMOUNT field by the amount of a nearly-equal share, so that
-- the sum of the shares exactly equals COST.

DECLARE
shares INTEGER;
error_term NUMERIC;

BEGIN

SELECT SUM(1) from temp WHERE reference = 'SHARE' into shares;

error_term := 0;
UPDATE temp SET amount = amount + calc_share( cost, shares, error_term )
WHERE reference = 'SHARE';

END;

$$ LANGUAGE PLPGSQL;

This example has the advantage of not requiring a primary key on
my temporary table, since the UPDATE statement ensures that each
record is processed in turn, with no ambiguity as to which record
is being updated.

However, the "calc_share" function has one INOUT parameter
"error_term" and an OUT parameter "result". From what I gather
so far, PL/pgSQL does not allow a function with OUT or INOUT
parameters to return a scalar result value. Based on that
understanding, my code looks like:

CREATE OR REPLACE FUNCTION share_cost( cost NUMERIC ) RETURNS VOID AS $$

-- Spread the amount COST across a number of records WHERE reference = 'SHARE'
-- increment the AMOUNT field by the amount of a nearly-equal share, so that
-- the sum of the shares exactly equals COST.

DECLARE
shares INTEGER;
error_term NUMERIC;
one_share NUMERIC;
share_record RECORD;

BEGIN

SELECT SUM(1) from temp WHERE reference = 'SHARE' into shares;

error_term := 0;
FOR share_record IN SELECT * FROM temp WHERE reference = 'SHARE' LOOP
SELECT error_term, result FROM calc_share( cost, shares, error_term ) INTO error_term, one_share;
UPDATE temp SET amount = amount + one_share
WHERE temp.acct_id = share_record.acct_id;
END LOOP;

END;

$$ LANGUAGE PLPGSQL;

So the simple UPDATE statement in the first example becomes a
somewhat clunky FOR loop in the second example, and the second
example also requires a primary key on acct_id to ensure that the
UPDATE and the FOR loop reference the same record.

Is that as good as this can get, or is there a simpler way, more
along the lines of the first version?

Thanks again for the education.

Jim

In response to

Responses

Browse pgsql-novice by date

  From Date Subject
Next Message Tim Landscheidt 2010-02-08 21:17:38 Re: Novice PL/pgSQL question and example
Previous Message peter 2010-02-08 18:34:56 Re: Incomplete pg_dump operation