views:

239

answers:

3

I have written a recursive function and depending on the output I need to select different fields. My question is now, how can I do this multiple times without having to call the function more then once? What I'm doing right now is just using the CASE WHEN... condition and checking every time what the functions return. (This is only a pseudo code and doesn't do anything real, it's just for understanding)

SELECT
id,
(CASE WHEN (function(id) > 0)
    THEN field1
    ELSE field2
END) as value1,
(CASE WHEN (function(id) > 0)
    THEN field3
    ELSE field4
END) as value2,
(CASE WHEN (function(id) > 0)
    THEN field5
    ELSE field6
END) as value3
FROM table1
...

How can I optimize this query and call the function only once? Thanks in advance!

+2  A: 

use a subquery :

SELECT foo, bar, result
FROM (
SELECT ..., function(id) AS result
....
) as tmp
chburd
A: 

If the function is declared IMMUTABLE, it is safe to call it many times, as it will not be reevaluated.

From the docs:

IMMUTABLE indicates that the function cannot modify the database and always returns the same result when given the same argument values; that is, it does not do database lookups or otherwise use information not directly present in its argument list. If this option is given, any call of the function with all-constant arguments can be immediately replaced with the function value.

Quassnoi
What happens if the result changes for the same arguments?
stefita
@stefita: you shouldn't mark such functions as `IMMUTABLE`. http://www.postgresql.org/docs/current/static/xfunc-volatility.html
Quassnoi
@stefita: You mean like clock_timestamp() ? Then you declare it VOLATILE and Postgres will invoke it every time it sees it. What else could it possibly do? But your example looks like function(id) returns the same thing but you need it to select 3 different fields
Adrian Pronk
@Adrian Pronk: the result of the function can change, since it selects a value from another table and it could be changed for that particular id.
stefita
@stefita: you should declare it as `STABLE` then. Within a query, the table state (as visible by the function) cannot change.
Quassnoi
Thank you! I think that `STABLE` is really the way to go.
stefita
There is no guarantee that such function will not be called many times! It is just hint for planner, and that's all.
depesz
@depesz: and what?
Quassnoi
A: 

You may be able to use some funky tuple thing like:

SELECT id,
CASE WHEN function(id) > 0
    THEN (field1, field3, field5)
    ELSE (field2, field4, field6)
END as (value1, value2, value3)

but I have no experience with this syntax

Adrian Pronk