3

Assume the following, rather simplistic database:

CREATE TABLE test_table(
  name TEXT,
  data JSONB
);
INSERT INTO test_table VALUES ('name1', '{"a": 1, "b": 2}'), ('name2', '{"c": 3, "d": 4, "e": 5}');

so we have the following table:

# SELECT * FROM test_table ;
 name  |           data
-------+--------------------------
 name1 | {"a": 1, "b": 2}
 name2 | {"c": 3, "d": 4, "e": 5}
(2 rows)

Now I've seen a query like this:

# SELECT * FROM test_table CROSS JOIN JSONB_EACH(test_table.data);

returning the following result:

 name  |           data           | key | value
-------+--------------------------+-----+-------
 name1 | {"a": 1, "b": 2}         | a   | 1
 name1 | {"a": 1, "b": 2}         | b   | 2
 name2 | {"c": 3, "d": 4, "e": 5} | c   | 3
 name2 | {"c": 3, "d": 4, "e": 5} | d   | 4
 name2 | {"c": 3, "d": 4, "e": 5} | e   | 5
(5 rows)

My problem is that I do not understand what happens here. On the one hand, this looks like a LATERAL join, since the right-hand side of JOIN refers to the left-hand one, and the result is perfectly logical. On the other hand, the manual says this:

(Without LATERAL, each sub-SELECT is evaluated independently and so cannot cross-reference any other FROM item.)

and this:

The column source table(s) must be INNER or LEFT joined to the LATERAL item […]

(see here), and of course the CROSS JOIN does not return n×m rows (as this page says).

My question is: does the result of the query above not contradict the manual? If not, does that mean that JSONB_EACH is somehow treated specially? (That I would find surprising.)

mbork
  • 564
  • 3
  • 23

1 Answers1

5

If not, does that mean that JSONB_EACH is somehow treated specially?

Yes it is, because it's a table function (aka "set returning function")

Quote from the manual

Table functions appearing in FROM can also be preceded by the key word LATERAL, but for functions the key word is optional; the function's arguments can contain references to columns provided by preceding FROM items in any case.

(emphasis mine)

  • 1
    It is optional for not just table functions, but actually for any functions. Postgres can even optimize to not use lateral at all if you actually don't refer to any of the previous table(s) and/or column(s) -- which is a bit annoying in some special cases i.e. https://rextester.com/WSZR96195 – pozs Oct 08 '19 at 18:56
  • so, may i inquire: ¿Can I understand or see a table functions as a kind of lateral subquery? – Victor Aug 29 '21 at 16:20