Repository: tobymao/sqlglot

Issue:
UNPIVOT expression with subquery alias fails
Hi!

We encounter an issue with trying to parse a BigQuery query that contains an UNPIVOT statement with an aliased sub query.
An example query that fails:

```
SELECT *
FROM (SELECT * FROM db.`my-table`) AS a
 UNPIVOT (
   (column) FOR column_name IN (value1, value2)
)
```

The stack trace we receive is:
```
Traceback (most recent call last):
  File "/Users/shay/Work/sql-lineage/query_analyzer.py", line 22, in __init__
    expressions = sqlglot.parse(self.query, self.dialect)
  File "/Users/shay/.local/share/virtualenvs/sql-lineage-XcD5rJZj/lib/python3.8/site-packages/sqlglot/__init__.py", line 72, in parse
    return dialect.parse(sql, **opts)
  File "/Users/shay/.local/share/virtualenvs/sql-lineage-XcD5rJZj/lib/python3.8/site-packages/sqlglot/dialects/dialect.py", line 163, in parse
    return self.parser(**opts).parse(self.tokenizer.tokenize(sql), sql)
  File "/Users/shay/.local/share/virtualenvs/sql-lineage-XcD5rJZj/lib/python3.8/site-packages/sqlglot/parser.py", line 775, in parse
    return self._parse(
  File "/Users/shay/.local/share/virtualenvs/sql-lineage-XcD5rJZj/lib/python3.8/site-packages/sqlglot/parser.py", line 841, in _parse
    self.raise_error("Invalid expression / Unexpected token")
  File "/Users/shay/.local/share/virtualenvs/sql-lineage-XcD5rJZj/lib/python3.8/site-packages/sqlglot/parser.py", line 884, in raise_error
    raise error
sqlglot.errors.ParseError: Invalid expression / Unexpected token. Line 4, Col: 2.
```

Thank you for your help and your great project!!!


Discussion:
@ShayYaari accordin to the spec the alias has to go after the pivot, is your query correct?
@tobymao Yes, I tried to run in a BigQuery playground and it seems to be valid.

Resolving patch:
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -1359,8 +1359,8 @@ def subquery_sql(self, expression: exp.Subquery, sep: str = " AS ") -> str:
         sql = self.query_modifiers(
             expression,
             self.wrap(expression),
-            self.expressions(expression, key="pivots", sep=" "),
             alias,
+            self.expressions(expression, key="pivots", sep=" "),
         )
 
         return self.prepend_ctes(expression, sql)
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -2085,6 +2085,8 @@ def _parse_table(
         subquery = self._parse_select(table=True)
 
         if subquery:
+            if not subquery.args.get("pivots"):
+                subquery.set("pivots", self._parse_pivots())
             return subquery
 
         this = self._parse_table_parts(schema=schema)


Test patch:
diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py
--- a/tests/dialects/test_bigquery.py
+++ b/tests/dialects/test_bigquery.py
@@ -8,6 +8,9 @@ class TestBigQuery(Validator):
     def test_bigquery(self):
         self.validate_identity("SELECT STRUCT<ARRAY<STRING>>(['2023-01-17'])")
         self.validate_identity("SELECT * FROM q UNPIVOT(values FOR quarter IN (b, c))")
+        self.validate_identity(
+            "SELECT * FROM (SELECT * FROM `t`) AS a UNPIVOT((c) FOR c_name IN (v1, v2))"
+        )
 
         self.validate_all("LEAST(x, y)", read={"sqlite": "MIN(x, y)"})
         self.validate_all(