Repository: tobymao/sqlglot

Issue:
Optimizer produces a group by with duplicated columns
1. Use the tpch query: https://github.com/dragansah/tpch-dbgen/blob/master/queries/18.sql

```sql
q = sqlglot.parse_one(QUERY)
```

Use the following schema (from tpch):

```
SCHEMA_DICT = {
    "REGION": {
        "R_REGIONKEY": "SERIAL PRIMARY KEY",
        "R_NAME": "CHAR(25)",
        "R_COMMENT": "VARCHAR(152)"
    },
    "NATION": {
        "N_NATIONKEY": "SERIAL PRIMARY KEY",
	    "N_NAME": "CHAR(25)",
	    "N_REGIONKEY": "BIGINT NOT NULL",
	    "N_COMMENT": "VARCHAR(152)"
    },
    "LINEITEM": {
        "L_ORDERKEY": "BIGINT NOT NULL",
	    "L_PARTKEY": "BIGINT NOT NULL",
	    "L_SUPPKEY": "BIGINT NOT NULL",
	    "L_LINENUMBER": "INTEGER",
        "L_QUANTITY": "DECIMAL",
	    "L_EXTENDEDPRICE": "DECIMAL",
	    "L_DISCOUNT": "DECIMAL",
	    "L_TAX": "DECIMAL",
        "L_RETURNFLAG": "CHAR(1)",
	    "L_LINESTATUS": "CHAR(1)",
	    "L_SHIPDATE": "DATE",
	    "L_COMMITDATE": "DATE",
	    "L_RECEIPTDATE": "DATE",
	    "L_SHIPINSTRUCT": "CHAR(25)",
	    "L_SHIPMODE": "CHAR(10)",
	    "L_COMMENT": "VARCHAR(44)",
    },
    "ORDERS": {
        "O_ORDERKEY": "SERIAL PRIMARY KEY",
	    "O_CUSTKEY": "BIGINT NOT NULL",
	    "O_ORDERSTATUS": "CHAR(1)",
	    "O_TOTALPRICE": "DECIMAL",
	    "O_ORDERDATE": "DATE",
	    "O_ORDERPRIORITY": "CHAR(15)",
	    "O_CLERK": "CHAR(15)",
	    "O_SHIPPRIORITY": "INTEGER",
	    "O_COMMENT": "VARCHAR(79)"
    },
    "CUSTOMER": {
        "C_CUSTKEY": "SERIAL PRIMARY KEY",
        "C_NAME": "VARCHAR(25)",
        "C_ADDRESS": "VARCHAR(40)",
        "C_NATIONKEY": "BIGINT NOT NULL",
        "C_PHONE": "CHAR(15)",
        "C_ACCTBAL": "DECIMAL",
        "C_MKTSEGMENT": "CHAR(10)",
        "C_COMMENT": "VARCHAR(117)"
    }
}
```

3. Then use the optimizer:

```
from sqlglot.optimizer import optimize
print(optimize(q, SCHEMA_DICT).sql(pretty=True))
```


The output is:

```
WITH "_u_0" AS (
  SELECT
    "lineitem"."l_orderkey" AS "l_orderkey"
  FROM "lineitem" AS "lineitem"
  GROUP BY
    "lineitem"."l_orderkey",
    "lineitem"."l_orderkey"
  HAVING
    SUM("lineitem"."l_quantity") > 10
)
SELECT
  "customer"."c_custkey" AS "c_custkey",
  "orders"."o_orderkey" AS "o_orderkey",
  "orders"."o_orderdate" AS "o_orderdate",
  "orders"."o_totalprice" AS "o_totalprice",
  SUM("lineitem"."l_quantity") AS "_col_4"
FROM "customer" AS "customer"
JOIN "orders" AS "orders"
  ON "customer"."c_custkey" = "orders"."o_custkey"
LEFT JOIN "_u_0" AS "_u_0"
  ON "_u_0"."l_orderkey" = "orders"."o_orderkey"
JOIN "lineitem" AS "lineitem"
  ON "lineitem"."l_orderkey" = "orders"."o_orderkey"
WHERE
  NOT "_u_0"."l_orderkey" IS NULL
GROUP BY
  "customer"."c_name",
  "customer"."c_custkey",
  "orders"."o_orderkey",
  "orders"."o_orderdate",
  "orders"."o_totalprice"
ORDER BY
  "o_totalprice" DESC,
  "o_orderdate"
```

and honestly I don't understand why, within the WITH "_u_0" there is a double group by that groups by the "lineitem"."l_orderkey".

Thanks! 


Discussion:
Interesting, thanks for reporting - I'll take a look.

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
@@ -94,8 +94,20 @@ def unnest(select, parent_select, next_alias_name):
     else:
         _replace(predicate, join_key_not_null)
 
+    group = select.args.get("group")
+
+    if group:
+        if {value.this} != set(group.expressions):
+            select = (
+                exp.select(exp.column(value.alias, "_q"))
+                .from_(select.subquery("_q", copy=False), copy=False)
+                .group_by(exp.column(value.alias, "_q"), copy=False)
+            )
+    else:
+        select = select.group_by(value.this, copy=False)
+
     parent_select.join(
-        select.group_by(value.this, copy=False),
+        select,
         on=column.eq(join_key),
         join_type="LEFT",
         join_alias=alias,


Test patch:
diff --git a/tests/fixtures/optimizer/tpc-h/tpc-h.sql b/tests/fixtures/optimizer/tpc-h/tpc-h.sql
--- a/tests/fixtures/optimizer/tpc-h/tpc-h.sql
+++ b/tests/fixtures/optimizer/tpc-h/tpc-h.sql
@@ -1047,7 +1047,6 @@ WITH "_u_0" AS (
     "lineitem"."l_orderkey" AS "l_orderkey"
   FROM "lineitem" AS "lineitem"
   GROUP BY
-    "lineitem"."l_orderkey",
     "lineitem"."l_orderkey"
   HAVING
     SUM("lineitem"."l_quantity") > 300
diff --git a/tests/fixtures/optimizer/unnest_subqueries.sql b/tests/fixtures/optimizer/unnest_subqueries.sql
--- a/tests/fixtures/optimizer/unnest_subqueries.sql
+++ b/tests/fixtures/optimizer/unnest_subqueries.sql
@@ -25,6 +25,7 @@ WHERE
   AND x.a > ALL (SELECT y.c FROM y WHERE y.a = x.a)
   AND x.a > (SELECT COUNT(*) as d FROM y WHERE y.a = x.a)
   AND x.a = SUM(SELECT 1)  -- invalid statement left alone
+  AND x.a IN (SELECT max(y.b) AS b FROM y GROUP BY y.a)
 ;
 SELECT
   *
@@ -155,6 +156,20 @@ LEFT JOIN (
     y.a
 ) AS _u_21
   ON _u_21._u_22 = x.a
+LEFT JOIN (
+  SELECT
+    _q.b
+  FROM (
+    SELECT
+      MAX(y.b) AS b
+    FROM y
+    GROUP BY
+      y.a
+  ) AS _q
+  GROUP BY
+    _q.b
+) AS _u_24
+  ON x.a = _u_24.b
 WHERE
   x.a = _u_0.a
   AND NOT _u_1.a IS NULL
@@ -212,6 +227,7 @@ WHERE
   AND x.a > COALESCE(_u_21.d, 0)
   AND x.a = SUM(SELECT
     1) /* invalid statement left alone */
+  AND NOT _u_24.b IS NULL
 ;
 SELECT
   CAST((