diff --git a/crates/polars-sql/src/sql_expr.rs b/crates/polars-sql/src/sql_expr.rs index 9e068efb6064..a2ada46e1c68 100644 --- a/crates/polars-sql/src/sql_expr.rs +++ b/crates/polars-sql/src/sql_expr.rs @@ -919,7 +919,7 @@ impl SQLExprVisitor<'_> { } let else_res = match else_result { Some(else_res) => self.visit_expr(else_res)?, - None => polars_bail!(SQLSyntax: "ELSE expression is required"), + None => lit(Null), // ELSE clause is optional; when omitted, it is implicitly NULL }; if let Some(operand_expr) = operand { let first_operand_expr = self.visit_expr(operand_expr)?; diff --git a/py-polars/tests/unit/sql/test_conditional.py b/py-polars/tests/unit/sql/test_conditional.py index b2000ebe37b1..3a80c1234aff 100644 --- a/py-polars/tests/unit/sql/test_conditional.py +++ b/py-polars/tests/unit/sql/test_conditional.py @@ -36,6 +36,24 @@ def test_case_when() -> None: } +@pytest.mark.parametrize("else_clause", ["ELSE NULL ", ""]) +def test_case_when_optional_else(else_clause: str) -> None: + df = pl.DataFrame( + { + "a": [1, 2, 3, 4, 5, 6, 7], + "b": [7, 6, 5, 4, 3, 2, 1], + "c": [3, 4, 0, 3, 4, 1, 1], + } + ) + query = f""" + SELECT + AVG(CASE WHEN a <= b THEN c {else_clause}END) AS conditional_mean + FROM self + """ + res = df.sql(query) + assert res.to_dict(as_series=False) == {"conditional_mean": [2.5]} + + def test_control_flow(foods_ipc_path: Path) -> None: nums = pl.LazyFrame( {