Repository: tobymao/sqlglot

Issue:
Sqlglot produces Syntax Error on rewriting QUALIFY
```python
print(
    sqlglot.parse_one(
        "SELECT tr.`User_-_iD`, tr.time_stamp, tr.__is_deleted, tr.__timestamp FROM tmp_9154874609124146377 AS tr WHERE __timestamp > CAST('2024-05-14 10:09:06.470000+00:00' AS TIMESTAMP) QUALIFY ROW_NUMBER() OVER (PARTITION BY `User_-_iD` ORDER BY __timestamp DESC) = 1",
        dialect="databricks",
    ).sql("spark")
)

```
this produces:

```sql
SELECT User_ - _iD, time_stamp, __is_deleted, __timestamp FROM (SELECT tr.`User_-_iD`, tr.time_stamp, tr.__is_deleted, tr.__timestamp, ROW_NUMBER() OVER (PARTITION BY `User_-_iD` ORDER BY __timestamp DESC) AS _w FROM tmp_9154874609124146377 AS tr WHERE __timestamp > CAST('2024-05-14 10:09:06.470000+00:00' AS TIMESTAMP)) AS _t WHERE _w = 1
```
`User_ - _iD` MUST be quoted for Spark, the rewrite should keep the quote here or just quote by default in the rewrite


Discussion:

Patch:
diff --git a/sqlglot/transforms.py b/sqlglot/transforms.py
index ec2a0df0..c214768d 100644
--- a/sqlglot/transforms.py
+++ b/sqlglot/transforms.py
@@ -105,7 +105,15 @@ def eliminate_qualify(expression: exp.Expression) -> exp.Expression:
                 select.replace(exp.alias_(select, alias))
                 taken.add(alias)
 
-        outer_selects = exp.select(*[select.alias_or_name for select in expression.selects])
+        def _is_quoted(select: exp.Expression) -> t.Optional[bool]:
+            return (select.args.get("alias") or select.this).args.get("quoted")
+
+        outer_selects = exp.select(
+            *[
+                exp.column(select.alias_or_name, quoted=_is_quoted(select))
+                for select in expression.selects
+            ]
+        )
         qualify_filters = expression.args["qualify"].pop().this
         expression_by_alias = {
             select.alias: select.this


Test patch:
diff --git a/tests/dialects/test_dialect.py b/tests/dialects/test_dialect.py
index 108ba216..09e8578b 100644
--- a/tests/dialects/test_dialect.py
+++ b/tests/dialects/test_dialect.py
@@ -2235,6 +2235,20 @@ SELECT
             },
         )
 
+    def test_qualify_spaces(self):
+        self.validate_all(
+            'SELECT "user id", some_id, 1 as other_id, 2 as "2 nd id" FROM t QUALIFY COUNT(*) OVER () > 1',
+            write={
+                "duckdb": 'SELECT "user id", some_id, 1 AS other_id, 2 AS "2 nd id" FROM t QUALIFY COUNT(*) OVER () > 1',
+                "snowflake": 'SELECT "user id", some_id, 1 AS other_id, 2 AS "2 nd id" FROM t QUALIFY COUNT(*) OVER () > 1',
+                "clickhouse": 'SELECT "user id", some_id, other_id, "2 nd id" FROM (SELECT "user id", some_id, 1 AS other_id, 2 AS "2 nd id", COUNT(*) OVER () AS _w FROM t) AS _t WHERE _w > 1',
+                "mysql": "SELECT `user id`, some_id, other_id, `2 nd id` FROM (SELECT `user id`, some_id, 1 AS other_id, 2 AS `2 nd id`, COUNT(*) OVER () AS _w FROM t) AS _t WHERE _w > 1",
+                "oracle": 'SELECT "user id", some_id, other_id, "2 nd id" FROM (SELECT "user id", some_id, 1 AS other_id, 2 AS "2 nd id", COUNT(*) OVER () AS _w FROM t) _t WHERE _w > 1',
+                "postgres": 'SELECT "user id", some_id, other_id, "2 nd id" FROM (SELECT "user id", some_id, 1 AS other_id, 2 AS "2 nd id", COUNT(*) OVER () AS _w FROM t) AS _t WHERE _w > 1',
+                "tsql": "SELECT [user id], some_id, other_id, [2 nd id] FROM (SELECT [user id] AS [user id], some_id AS some_id, 1 AS other_id, 2 AS [2 nd id], COUNT(*) OVER () AS _w FROM t) AS _t WHERE _w > 1",
+            },
+        )
+
     def test_nested_ctes(self):
         self.validate_all(
             "SELECT * FROM (WITH t AS (SELECT 1 AS c) SELECT c FROM t) AS subq",