Skip to content

Commit

Permalink
feat(clickhouse): support scalar CTE in query builder (#4590)
Browse files Browse the repository at this point in the history
Example:

```python
select("x")
.with_("v", as_=select("foo").from_("bar"), scalar=True)
.from_("t")
.where("id = v")
```

```sql
WITH (SELECT foo FROM bar) AS v
SELECT x FROM t WHERE id = v
```
  • Loading branch information
pkit authored Jan 9, 2025
1 parent 986a1da commit 3bfd6de
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 2 deletions.
11 changes: 9 additions & 2 deletions sqlglot/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,7 @@ def with_(
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
scalar: bool = False,
**opts,
) -> Q:
"""
Expand All @@ -1244,6 +1245,7 @@ def with_(
Otherwise, this resets the expressions.
dialect: the dialect used to parse the input expression.
copy: if `False`, modify this expression instance in-place.
scalar: if `True`, this is a scalar common table expression.
opts: other options to use to parse the input expressions.
Returns:
Expand All @@ -1258,6 +1260,7 @@ def with_(
append=append,
dialect=dialect,
copy=copy,
scalar=scalar,
**opts,
)

Expand Down Expand Up @@ -7036,11 +7039,15 @@ def _apply_cte_builder(
append: bool = True,
dialect: DialectType = None,
copy: bool = True,
scalar: bool = False,
**opts,
) -> E:
alias_expression = maybe_parse(alias, dialect=dialect, into=TableAlias, **opts)
as_expression = maybe_parse(as_, dialect=dialect, **opts)
cte = CTE(this=as_expression, alias=alias_expression, materialized=materialized)
as_expression = maybe_parse(as_, dialect=dialect, copy=copy, **opts)
if scalar and not isinstance(as_expression, Subquery):
# scalar CTE must be wrapped in a subquery
as_expression = Subquery(this=as_expression)
cte = CTE(this=as_expression, alias=alias_expression, materialized=materialized, scalar=scalar)
return _apply_child_list_builder(
cte,
instance=instance,
Expand Down
16 changes: 16 additions & 0 deletions tests/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,22 @@ def test_build(self):
lambda: exp.union("SELECT 1", "SELECT 2", "SELECT 3", "SELECT 4"),
"SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4",
),
(
lambda: select("x")
.with_("var1", as_=select("x").from_("tbl2").subquery(), scalar=True)
.from_("tbl")
.where("x > var1"),
"WITH (SELECT x FROM tbl2) AS var1 SELECT x FROM tbl WHERE x > var1",
"clickhouse",
),
(
lambda: select("x")
.with_("var1", as_=select("x").from_("tbl2"), scalar=True)
.from_("tbl")
.where("x > var1"),
"WITH (SELECT x FROM tbl2) AS var1 SELECT x FROM tbl WHERE x > var1",
"clickhouse",
),
]:
with self.subTest(sql):
self.assertEqual(expression().sql(dialect[0] if dialect else None), sql)

0 comments on commit 3bfd6de

Please sign in to comment.