Repository: tobymao/sqlglot

Issue:
window frame generates incorrect sql when aliased
Parsing an empty window frame and then generating the SQL from it produces a reference to a non-existent named window frame.

```
In [1]: import sqlglot as sg

In [2]: sg.alias(sg.parse_one("LAG(x) over ()"), "a").sql()
Out[2]: 'LAG(x) OVER a'
```

When the window frame has a `PARTITION BY` or `ORDER BY` or both, the result is also incorrect but for a different reason

Only `PARTITION BY`:

```
In [3]: sg.alias(sg.parse_one("LAG(x) over (partition by y)"), "a").sql()
Out[3]: 'LAG(x) OVER (aPARTITION BY y)'
```

Only `ORDER BY`:

```
In [4]: sg.alias(sg.parse_one("LAG(x) over (order by y)"), "a").sql()
Out[4]: 'LAG(x) OVER (aORDER BY y)'
```

Both `PARTITION BY` and `ORDER BY`:

```
In [5]: sg.alias(sg.parse_one("LAG(x) over (partition by y order by z)"), "a").sql()
Out[5]: 'LAG(x) OVER (aPARTITION BY y ORDER BY z)'
```

The desired result is:

```
In [5]: sg.alias(sg.parse_one("LAG(x) over (partition by y order by z)"), "a").sql()
Out[5]: 'LAG(x) OVER (PARTITION BY y ORDER BY z) AS a'
```


Discussion:

Resolving patch:
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -3150,7 +3150,7 @@ def alias_(expression, alias, table=False, dialect=None, quoted=None, **opts):
     alias = to_identifier(alias, quoted=quoted)
     alias = TableAlias(this=alias) if table else alias
 
-    if "alias" in exp.arg_types:
+    if "alias" in exp.arg_types and not isinstance(exp, Window):
         exp = exp.copy()
         exp.set("alias", alias)
         return exp


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
@@ -152,6 +152,10 @@ def test_bigquery(self):
             "SELECT ROW() OVER (y ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM x WINDOW y AS (PARTITION BY CATEGORY)"
         )
 
+        self.validate_identity(
+            "SELECT item, purchases, LAST_VALUE(item) OVER (item_window ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING) AS most_popular FROM Produce WINDOW item_window AS (ORDER BY purchases)"
+        )
+
         self.validate_identity(
             "SELECT LAST_VALUE(a IGNORE NULLS) OVER y FROM x WINDOW y AS (PARTITION BY CATEGORY)",
         )
diff --git a/tests/test_build.py b/tests/test_build.py
--- a/tests/test_build.py
+++ b/tests/test_build.py
@@ -1,6 +1,7 @@
 import unittest
 
 from sqlglot import (
+    alias,
     and_,
     condition,
     except_,
@@ -364,6 +365,22 @@ def test_build(self):
                 lambda: parse_one("(SELECT * FROM foo)").union("SELECT * FROM bla", distinct=False),
                 "(SELECT * FROM foo) UNION ALL SELECT * FROM bla",
             ),
+            (
+                lambda: alias(parse_one("LAG(x) OVER (PARTITION BY y)"), "a"),
+                "LAG(x) OVER (PARTITION BY y) AS a",
+            ),
+            (
+                lambda: alias(parse_one("LAG(x) OVER (ORDER BY z)"), "a"),
+                "LAG(x) OVER (ORDER BY z) AS a",
+            ),
+            (
+                lambda: alias(parse_one("LAG(x) OVER (PARTITION BY y ORDER BY z)"), "a"),
+                "LAG(x) OVER (PARTITION BY y ORDER BY z) AS a",
+            ),
+            (
+                lambda: alias(parse_one("LAG(x) OVER ()"), "a"),
+                "LAG(x) OVER () AS a",
+            ),
         ]:
             with self.subTest(sql):
                 self.assertEqual(expression().sql(dialect[0] if dialect else None), sql)