diff --git a/ibis/backends/sql/rewrites.py b/ibis/backends/sql/rewrites.py index 783ff10ea968..554508a3d8ff 100644 --- a/ibis/backends/sql/rewrites.py +++ b/ibis/backends/sql/rewrites.py @@ -102,6 +102,12 @@ def dtype(self): return self.func.dtype +# TODO(kszucs): there is a better strategy to rewrite the relational operations +# to Select nodes by wrapping the leaf nodes in a Select node and then merging +# Project, Filter, Sort, etc. incrementally into the Select node. This way we +# can have tighter control over simplification logic. + + @replace(p.Project) def project_to_select(_, **kwargs): """Convert a Project node to a Select node.""" @@ -164,20 +170,20 @@ def merge_select_select(_, **kwargs): for v in _.predicates: if v.find((ops.ExistsSubquery, ops.InSubquery), filter=ops.Value): return _ + # cannot merge if the inner select has different order keys than the outer + if _.sort_keys and _.parent.sort_keys: + return _ subs = {ops.Field(_.parent, k): v for k, v in _.parent.values.items()} selections = {k: v.replace(subs, filter=ops.Value) for k, v in _.selections.items()} predicates = tuple(p.replace(subs, filter=ops.Value) for p in _.predicates) sort_keys = tuple(s.replace(subs, filter=ops.Value) for s in _.sort_keys) - unique_predicates = toolz.unique(_.parent.predicates + predicates) - unique_sort_keys = {s.expr: s for s in _.parent.sort_keys + sort_keys} - return Select( _.parent.parent, selections=selections, - predicates=unique_predicates, - sort_keys=unique_sort_keys.values(), + predicates=toolz.unique(_.parent.predicates + predicates), + sort_keys=_.parent.sort_keys + sort_keys, ) diff --git a/ibis/backends/tests/sql/snapshots/test_sql/test_double_order_by_not_fused/out.sql b/ibis/backends/tests/sql/snapshots/test_sql/test_double_order_by_not_fused/out.sql new file mode 100644 index 000000000000..38ceb36268fc --- /dev/null +++ b/ibis/backends/tests/sql/snapshots/test_sql/test_double_order_by_not_fused/out.sql @@ -0,0 +1,13 @@ +SELECT + "t1"."a", + "t1"."b" +FROM ( + SELECT + "t0"."a", + "t0"."b" + FROM "t" AS "t0" + ORDER BY + "t0"."a" ASC +) AS "t1" +ORDER BY + "t1"."b" DESC \ No newline at end of file diff --git a/ibis/backends/tests/sql/test_sql.py b/ibis/backends/tests/sql/test_sql.py index d4bb8fe8033e..b52f97451f9e 100644 --- a/ibis/backends/tests/sql/test_sql.py +++ b/ibis/backends/tests/sql/test_sql.py @@ -518,6 +518,12 @@ def test_order_by_expr(snapshot): snapshot.assert_match(to_sql(expr), "out.sql") +def test_double_order_by_not_fused(snapshot): + t = ibis.table(dict(a="int", b="string"), name="t") + expr = t.order_by(t.a).order_by(t.b.desc()) + snapshot.assert_match(to_sql(expr), "out.sql") + + def test_no_cartesian_join(snapshot): customers = ibis.table( dict(customer_id="int64", first_name="string", last_name="string"),