PostgreSQL’s New LATERAL Join Type
blog.heapanalytics.com
blog.heapanalytics.com
It's also great for set returning functions. Even cooler, you don't need to explicitly specify the LATERAL keyword. The query planner will add it for you automatically:
-- NOTE: WITH clause is just to fake a table with data:
WITH foo AS (
SELECT 'a' AS name
, 2 AS quantity
UNION ALL
SELECT 'b' AS name
, 4 AS quantity)
SELECT t.*
, x
FROM foo t
-- No need to say "LATERAL" here as it's added automatically
, generate_series(1,quantity) x;
name | quantity | x
------+----------+---
a | 2 | 1
a | 2 | 2
b | 4 | 1
b | 4 | 2
b | 4 | 3
b | 4 | 4
(6 rows)Anyway, good that Postgres has it too, now. There are several Postgres features I'd love in SQL Server, like range types...
Agreed on range types.. proper enums in T-SQL would be nice too. I'm really liking where PL/v8 is going, and would like to see something similar in MS-SQL server as well.. the .Net extensions are just too much of a pain to do much with. It's be nice to have a syntax that makes working with custom data types, or even just JSON and XML easier.
If PostgreSQL adds built-in replication to the Open-Source version that isn't a hacky add-on, and has failover similar to, for example MongoDB's replica sets, I'm so pushing pg for most new projects.
Maria/MySQL seem to be getting interesting as well. Honestly, I like MS-SQL until the cost of running it gets a little wonky (Azure pricing going from a single instance to anything that can have replication for example). Some of Amazon's offerings are really getting compelling here.
For example, in SQL Server I find a common use of CROSS APPLY (which appears to be the same thing) is where the "table-valued function" is a SELECT with a WHERE clause referencing the earlier query, an ORDER BY, and a TOP (=LIMIT) 1. (In fact, this is exactly the example given in the article.) It allows you to do things like "for each row in table A, join the last row in table B where NaturalKey(A) = NaturalKey(B) and Value1(A) is greater than or equal to Value2(B)".
SELECT unnest(ar).* FROM
(SELECT ARRAY(SELECT tbl FROM tbl
WHERE .. ORDER BY .. LIMIT 2) AS ar
FROM .. OFFSET 0) ss;
If you want a specific set of columns instead of *, you'd need to create a custom composite type to create an array of, since it's not possible to "unpack" anonymous records.IMHO, it's a good thing if LATERAL is only added as some kind of syntactic sugar. I once had to use LATERAL in DB2 as a band-aid solution for its broken scoping rules: https://www.ibm.com/developerworks/mydeveloperworks/blogs/SQ...
SELECT id, COUNT(keys)
FROM users,
LATERAL json_object_keys(login_history) keys
GROUP BY id;"Loosely, it means that a LATERAL join is like a SQL foreach loop, in which PostgreSQL will iterate over each row in a result set and evaluate a subquery using that row as a parameter."
SELECT *
FROM employees e
WHERE EXISTS (SELECT 1
FROM employee_projects ep
WHERE ep.employee_id = e.id
AND ep.project_id = 5)
;
This new feature is a lot like correlated subqueries except you can put that nested SELECT into the FROM clause and still access the employees table.Also, you should probably show some explain plans before making this claim: "Without lateral joins, we would need to resort to PL/pgSQL to do this analysis. Or, if our data set were small, we could get away with complex, inefficient queries."
Here's a comparison of the explain plan from your query without the `sum(1)` and `order by...limit` business and a query using only left joins (no use of lateral): [link redacted]. Note, I ran this against an empty copy of your exact table (no data, no statistics). However, the explain plans are the same.
My understanding is that lateral was really meant for set returning functions like generate_series as others have already mentioned.
Edit: I should mention I know you were just trying to demonstrate how lateral works and that it is always good to see people writing about new Postgres features!
I don't buy the performance benefit over derived tables with properly indexed fields for this example. However, I'd definitely use this more so with functions.
In my own case it was so I could create a view that would give me a denormalized view of most of the data for a given record... most of the fields were in a common PROPERTIES table with some funky data in it... Sometimes normalization goes too far.
WITH RECURSIVE allows a query to refer its own results when computing its results. That may sound mind-bending, but it's really just poorly named way to do a "while" loop in SQL.
A WITH RECURSIVE has the form (base-case-query UNION ALL iterative-step-query). The query for the iterative step can refer to itself via the WITH alias. When it does so, it's actually operating on only those records produced by the previous step of the iteration. The iterative-step-query will execute possibly multiple times, stopping only when it doesn't produce any more records.
Here's the WITH RECURSIVE example from the Postgres docs, translated into Python:
all_records = []
previous_step = [1] # base case, i.e. "VALUES (1)."
while previous_step:
all_records.extend(previous_step)
# iterative step, i.e. "SELECT n+1 FROM t WHERE n < 100"
current_step = [n+1 for n in previous_step if n < 100]
previous_step = current_step
The confusing part is that the alias "t" in the SQL example means different things in different places. Outside the WITH RECURSIVE, "t" is equivalent to "all_records" in the example. Within the WITH RECURSIVE definition, "t" is the same as "previous_step".Not trolling or trying to start a flame, I'm genuinely curious as to how people here get stuff done.
(ha ha, only serious)
Somethings i would have liked to have read/seen though are, the hardware specs, database dimensions (nr of entries in tables etc) and query times.
Just my penny. Hope you can spend it still somewhere :)
i.e.
SELECT a, (SELECT b FROM ...) b FROM ....https://news.ycombinator.com/item?id=8690389
But they are similar... Kind of like correlated subqueries in the from clause. But they allow a few new twists in the semantics.