I don't think that the point was that there are no for loops in SQL. I think the point was that almost always using for loops is wrong and super inefficient and there is a much more efficient way to just use joins instead.
What does it matter? Yeah, at the very bottom of it all there will be a loop. I wouldn't attribute that to C but to the von Neumann architecture.
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.
Exactly, SQL is like a very specific natural language used to tell a database what data you need. The database contains AI (the query optimizer) that will use statistics to determine the fastest way to retrieve the data requested. Depending on your query and the data you have the fastest way to get your data will change. It’s hard to manually write this yourself.
For this example, nothing. It would be useful where neither of the two SELECT queries is a subset/superset of the other. (Not saying you didn't know that.)
This will be useful if you have a table with some related history records, e.g., products with product price history, and you want to get the latest price. The lateral join would get all prices for the current product, sort them by date and then pick the top row.
But generating a table with all numbers was just a throwaway example of the LATERAL JOIN syntax/use, and (hopefully) not what you'd actually use it for in the real world.
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).
I love LATERALs, but this still fits within set theory and a bulk application rather than an iterative for-loop. It may even be implemented as a for-loop within the engine, but SQL being declarative abstracts that away from the query interface.
It'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;
At the very least mention that re-running the SELECT in the same connection would include the prior results as well because they are preserved across commands within the same connection.
Ha! plpgsql's seemingly sole purpose is to inject imperative code into a set-based environment. Probably does it more smoothly than most pl languages, but that's at the cost of imperative clarity.
But you're right. Postgres does allow for-loops like this. (They're also slower than the equivalent set-oriented approach.)
Ever heard of LATERAL joins/CROSS APPLY?