Ever heard of LATERAL joins/CROSS APPLY?
SELECT loop.value, x.squared
FROM generate_series(1,5) AS loop(value)
CROSS JOIN LATERAL (SELECT loop.value * loop.value AS squared) AS x;Ever heard of LATERAL joins/CROSS APPLY?
SELECT loop.value, x.squared
FROM generate_series(1,5) AS loop(value)
CROSS JOIN LATERAL (SELECT loop.value * loop.value AS squared) AS x;The reason people use a relational database is because it has loops that are faster, safer, and more efficient than anything you can write.
The point is that by getting rid of loops you remove one way of telling the computer "How" to do it. Start here, do it in this order, combine the data this way.
When "How" is a solved problem, it is a waste of your brain to think about that again. "What" is a better use of your brain cycles.
different kind of loops can be different, e.g. 2 nested loop with quadratic time:
for i in t1: for j in t2:
vs sort + merge join with n log n time.
And this is the point I was trying to make.
Instead of start with the "how", learn to do the "what".
SELECT loop.value, loop.value * loop.value
FROM generate_series(1,5) AS loop(value)WITH RECURSIVE cnt(x) AS ( SELECT 1 UNION ALL SELECT x+1 FROM cnt LIMIT 5 ) SELECT x FROM cnt;
And then do a regular CROSS JOIN on that table.
It's not clear to me that (mathematically) a lateral join can be reduced to a recursive cte (and if the performance of a recursive cte would be acceptable for the cases where it does work as a substitute).
- Reference data from the previous part of the query (the "left-hand side")
- Return multiple columns
The only way you can achieve it is with LATERAL/CROSS APPLY.
Regular correlated subqueries can only return a single column, so something like this doesn't work:
SELECT
loop.val, (SELECT loop.val * loop.val, 'second column') AS squared
FROM
(SELECT loop.val FROM generate_series(1,5) AS loop(val)) as loop
You'd get: error: subquery must return only one columnIt's sets all the way down. A set of f(x) is still a set.
CREATE TEMP TABLE temp_results(value int, value_squared int);
DO $$
DECLARE
r int;
BEGIN
FOR r IN SELECT generate_series FROM generate_series(1,5)
LOOP
INSERT INTO temp_results VALUES (r, r * r);
END LOOP;
END$$;
SELECT * FROM temp_results;But you're right. Postgres does allow for-loops like this. (They're also slower than the equivalent set-oriented approach.)
https://chat.openai.com/share/931b1778-6393-4e86-94b4-b3b5a5...