First of all I guess that query optimizer is smart enough to spot the same deterministic expressions and do not calculate it twice.
If this is not applicable you could use LATERAL
:
SELECT *,
CASE column1
WHEN sub.long_calc THEN 10
ELSE sub.long_calc + 2 * 3.14
END AS mycalc
FROM tab t
,LATERAL (VALUES(t.a+t.b+t.c)) AS sub(long_calc);
SqlFiddleDemo
Output:
╔═════╦══════════╦════╦════╦════╦════════════╦════════╗
║ id ║ column1 ║ a ║ b ║ c ║ long_calc ║ mycalc ║
╠═════╬══════════╬════╬════╬════╬════════════╬════════╣
║ 1 ║ 6 ║ 1 ║ 2 ║ 3 ║ 6 ║ 10 ║
║ 2 ║ 20 ║ 2 ║ 3 ║ 4 ║ 9 ║ 15.28 ║
╚═════╩══════════╩════╩════╩════╩════════════╩════════╝
You could replace VALUES
with simple SELECT
or function call:
-- any query
,LATERAL (SELECT t.a+t.b+t.c) AS sub(long_calc)
-- function
,LATERAL random() AS sub(long_calc)
-- function with parameter passing
,LATERAL sin(t.a) AS sub(long_calc)
SqlFiddleDemo2
EDIT:
SELECT id
,sub2.long_calc_rand -- calculated once
,random() AS rand -- calculated every time
FROM tab t
,LATERAL random() AS sub2(long_calc_rand);
SqlFiddleDemo3
Output:
╔═════╦═════════════════════╦════════════════════╗
║ id ║ long_calc_rand ║ rand ║
╠═════╬═════════════════════╬════════════════════╣
║ 1 ║ 0.3426254219375551 ║ 0.8861959744244814 ║
║ 2 ║ 0.3426254219375551 ║ 0.8792812027968466 ║
║ 3 ║ 0.3426254219375551 ║ 0.8123061805963516 ║
╚═════╩═════════════════════╩════════════════════╝