Repository: tobymao/sqlglot

Issue:
'Union' object has no attribute 'group_by'
```
from sqlglot import optimizer, parse_one

sql = "SELECT * FROM event WHERE priority = 'High' AND tagname IN (SELECT tag_input AS tagname FROM cascade WHERE tag_input = 'XXX' OR tag_output = 'XXX' UNION SELECT tag_output AS tagname FROM cascade WHERE tag_input = 'XXX' OR tag_output = 'XXX')"

q = parse_one(sql, "postgres")
oq = optimizer.optimize(q, dnf=True, dialect="postgres")
```

will produce the following error:
```Traceback (most recent call last):
  File "/Users/elham/Documents/KG_LLM/siwarex/api/exm/test.py", line 6, in <module>
    oq = optimizer.optimize(q, dnf=True, dialect="postgres")
  File "/Users/elham/anaconda3/envs/siwarex3/lib/python3.10/site-packages/sqlglot/optimizer/optimizer.py", line 92, in optimize
    expression = rule(expression, **rule_kwargs)
  File "/Users/elham/anaconda3/envs/siwarex3/lib/python3.10/site-packages/sqlglot/optimizer/unnest_subqueries.py", line 34, in unnest_subqueries
    unnest(select, parent, next_alias_name)
  File "/Users/elham/anaconda3/envs/siwarex3/lib/python3.10/site-packages/sqlglot/optimizer/unnest_subqueries.py", line 107, in unnest
    select = select.group_by(value.this, copy=False)
AttributeError: 'Union' object has no attribute 'group_by'
```


Discussion:

Resolving patch:
diff --git a/sqlglot/optimizer/unnest_subqueries.py b/sqlglot/optimizer/unnest_subqueries.py
--- a/sqlglot/optimizer/unnest_subqueries.py
+++ b/sqlglot/optimizer/unnest_subqueries.py
@@ -41,8 +41,6 @@ def unnest(select, parent_select, next_alias_name):
         return
 
     predicate = select.find_ancestor(exp.Condition)
-    alias = next_alias_name()
-
     if (
         not predicate
         or parent_select is not predicate.parent_select
@@ -50,6 +48,10 @@ def unnest(select, parent_select, next_alias_name):
     ):
         return
 
+    if isinstance(select, exp.Union):
+        select = exp.select(*select.selects).from_(select.subquery(next_alias_name()))
+
+    alias = next_alias_name()
     clause = predicate.find_ancestor(exp.Having, exp.Where, exp.Join)
 
     # This subquery returns a scalar and can just be converted to a cross join


Test patch:
diff --git a/tests/fixtures/optimizer/optimizer.sql b/tests/fixtures/optimizer/optimizer.sql
--- a/tests/fixtures/optimizer/optimizer.sql
+++ b/tests/fixtures/optimizer/optimizer.sql
@@ -1388,3 +1388,45 @@ WHERE
 ORDER BY
   COUNT(DISTINCT `cs1`.`cs_order_number`)
 LIMIT 100;
+
+# execute: false
+SELECT
+  *
+FROM event
+WHERE priority = 'High' AND tagname IN (
+  SELECT
+    tag_input AS tagname
+  FROM cascade
+  WHERE tag_input = 'XXX' OR tag_output = 'XXX'
+  UNION
+  SELECT
+    tag_output AS tagname
+  FROM cascade
+  WHERE tag_input = 'XXX' OR tag_output = 'XXX'
+);
+WITH "_u_0" AS (
+  SELECT
+    "cascade"."tag_input" AS "tagname"
+  FROM "cascade" AS "cascade"
+  WHERE
+    "cascade"."tag_input" = 'XXX' OR "cascade"."tag_output" = 'XXX'
+  UNION
+  SELECT
+    "cascade"."tag_output" AS "tagname"
+  FROM "cascade" AS "cascade"
+  WHERE
+    "cascade"."tag_input" = 'XXX' OR "cascade"."tag_output" = 'XXX'
+), "_u_1" AS (
+  SELECT
+    "cascade"."tag_input" AS "tagname"
+  FROM "_u_0" AS "_u_0"
+  GROUP BY
+    "cascade"."tag_input"
+)
+SELECT
+  *
+FROM "event" AS "event"
+LEFT JOIN "_u_1" AS "_u_1"
+  ON "_u_1"."tagname" = "event"."tagname"
+WHERE
+  "event"."priority" = 'High' AND NOT "_u_1"."tagname" IS NULL;