You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on May 16, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on May 16, 2026. It is now read-only.
Unnest Function In BigQuery SQLAlchemy Plugin Joins Twice When Selecting Other Columns in CTE or Subquery #368
WITH `cte` AS
(SELECT `table1`.`foo` AS `foo`, `bar`
FROM `table1`, `table1` `table1_1`, unnest(`table1_1`.`bars`) AS `bar`)
SELECT `cte`.`foo`, `cte`.`bar`
FROM `cte`
Note that table1 is duplicated in the FROM clause again.
Expected behavior: It is expected to generate the following query instead (note the different FROM clause):
WITH `cte` AS
(SELECT `table1`.`foo`, `bar`
FROM `table1`, unnest(`table1`.`bars`) AS `bar`)
SELECT `cte`.`foo`, `cte`.`bar`
FROM `cte`
That is probably what we want, since it "flattens" the array, but I wonder if we can make that cross-join more explicit to avoid issues like this? Perhaps we make unnest produce some kind of table-like object and force users to join themselves?
Perhaps we make unnest produce some kind of table-like object and force users to join themselves?
It's definitely possible that I'm using this wrong, and if there is a more explicit way to express this I'm happy to use that. FWIW the Postgres backend seems to be OK with this though:
WITH cte AS
(SELECTtable1.fooAS foo, bar
FROM table1, unnest(table1.bars) AS bar),
cte2 AS
(SELECTcte.fooAS foo, cte.barAS bar
FROM cte)
SELECTcte2.foo, cte2.barFROM cte2
Hello team! This issue has been open for some time now. I just wanted to make a comment to bring some visibility to the issue. @kwohlfahrt you mentioned that the linked PR fixed the issue as reported but you have another use case where you are uncertain whether you are using the product wrong. @tseaver how could we resolve this situation?
Since this look completely stagnant, someone knows some workaround it? Is possible to write the UNNEST(table.col) AS x as text in the FROM?
I tried using the solution of @kwohlfahrt but didn't work because I need to know the values inside the struct, so I had to use table_valued(). sel = select(func.UNNEST(table.c[self.output_attribute_id]).table_valued(*self.input_attribute_ids)).cte("cte") _compile_query(sel)
But it returns
SELECT `table_1`.`oo_single`, `anon_1`.`pp_single`, `anon_1`.`pp_total`
FROM
`table` `table_1`,
UNNEST(`table_1`.`pp_metrics`) AS `anon_1`
IMHO the original problematic code was fixed by #839, though there is still a scenario that is not handled:
When creating a statement using JOIN + UNNEST and then using it as a subquery for a new SELECT statement, it causes the table used in the UNNEST to be specified twice in the FROM statement, thus creating implicit JOIN between that table to itself.
Raw query
---------
SELECT table1.id, table2.dummy
FROM table2, unnest(table2.ids) AS unnested_ids JOIN table1 ON table1.id = unnested_ids
Compiled query
---------
SELECT `table1`.`id`, `table2`.`dummy`
FROM `table2`, unnest(`table2`.`ids`) AS `unnested_ids` JOIN `table1` ON `table1`.`id` = `unnested_ids`
Raw query
---------
SELECT *
FROM (SELECT table1.id AS id, table2.dummy AS dummy
FROM table2, unnest(table2.ids) AS unnested_ids JOIN table1 ON table1.id = unnested_ids) AS anon_1
Compiled query
---------
SELECT *
FROM (SELECT `table1`.`id` AS `id`, `table2`.`dummy` AS `dummy`
FROM `table2`, `table2` `table2_1`, unnest(`table2_1`.`ids`) AS `unnested_ids` JOIN `table1` ON `table1`.`id` = `unnested_ids`) AS `anon_1`1`
Thanks to @yuval-bavli for helping with pinpointing the scenario
Activity
tswast commentedon Oct 28, 2021
@tseaver Would you mind looking into this? Seems we need a follow-up to #361 to account for sub-queries and table-valued expressions.
fix: avoid aliasing known tables used in CTEs
tseaver commentedon Oct 28, 2021
PR #369 adds a fix for the CTE case. I tried to write a failing test using
subquery, but didn't manage to come up with a coherent one.I have a feeling that this is going to be whack-a-mole salad (e.g., nesting CTEs is likely still broken).
fix: avoid aliasing known tables used in CTEs (#369)
tswast commentedon Oct 29, 2021
I took a closer looks at this logic. The multiple "FROM" logic is technically a cross-join https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#comma_cross_join
That is probably what we want, since it "flattens" the array, but I wonder if we can make that cross-join more explicit to avoid issues like this? Perhaps we make
unnestproduce some kind of table-like object and force users to join themselves?kwohlfahrt commentedon Oct 29, 2021
Hi, I originally submitted the request, let me know if I can do anything to help.
The linked PR fixed the issue as reported:
but...
yup.
It's definitely possible that I'm using this wrong, and if there is a more explicit way to express this I'm happy to use that. FWIW the Postgres backend seems to be OK with this though:
tswast commentedon Nov 1, 2021
@kwohlfahrt thanks for the examples and the note regarding Postgres.
mgtcardenas commentedon Nov 22, 2021
Hello team! This issue has been open for some time now. I just wanted to make a comment to bring some visibility to the issue. @kwohlfahrt you mentioned that the linked PR fixed the issue as reported but you have another use case where you are uncertain whether you are using the product wrong. @tseaver how could we resolve this situation?
lazjake commentedon Jun 27, 2022
👋 any progress on this one? sadly running into the nested cte issue 😢
set92 commentedon Nov 18, 2022
Since this look completely stagnant, someone knows some workaround it? Is possible to write the
UNNEST(table.col) AS xas text in the FROM?I tried using the solution of @kwohlfahrt but didn't work because I need to know the values inside the struct, so I had to use table_valued().
sel = select(func.UNNEST(table.c[self.output_attribute_id]).table_valued(*self.input_attribute_ids)).cte("cte") _compile_query(sel)But it returns
which basically duplicates the data.
jlynchMicron commentedon Mar 15, 2023
I am getting this issue when trying to unnest an array of structs, similar to this issue: googleapis/google-cloud-python#15809
evakill commentedon Oct 24, 2023
@lazjake oh hi - still an issue 🫠
snapiri commentedon Nov 26, 2023
IMHO the original problematic code was fixed by #839, though there is still a scenario that is not handled:
When creating a statement using JOIN + UNNEST and then using it as a subquery for a new SELECT statement, it causes the table used in the UNNEST to be specified twice in the FROM statement, thus creating implicit JOIN between that table to itself.
Example code:
Which prints the following:
Thanks to @yuval-bavli for helping with pinpointing the scenario