Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions sqlglot/dialects/duckdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,15 @@ def _cast_to_blob(self: DuckDB.Generator, expression: exp.Expression, result_sql
return result_sql


def _anyvalue_sql(self: DuckDB.Generator, expression: exp.AnyValue) -> str:
# Transform ANY_VALUE(expr HAVING MAX/MIN having_expr) to ARG_MAX_NULL/ARG_MIN_NULL
having = expression.this
if isinstance(having, exp.HavingMax):
func_name = "ARG_MAX_NULL" if having.args.get("max") else "ARG_MIN_NULL"
return self.func(func_name, having.this, having.expression)
return self.function_fallback_sql(expression)


class DuckDB(Dialect):
NULL_ORDERING = "nulls_are_last"
SUPPORTS_USER_DEFINED_TYPES = True
Expand Down Expand Up @@ -699,6 +708,7 @@ class Generator(generator.Generator):

TRANSFORMS = {
**generator.Generator.TRANSFORMS,
exp.AnyValue: _anyvalue_sql,
exp.ApproxDistinct: approx_count_distinct_sql,
exp.Array: transforms.preprocess(
[transforms.inherit_struct_field_names],
Expand Down
27 changes: 27 additions & 0 deletions tests/dialects/test_bigquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,33 @@ def test_bigquery(self):
self.validate_identity("SELECT PARSE_TIMESTAMP('%c', 'Thu Dec 25 07:30:00 2008', 'UTC')")
self.validate_identity("SELECT ANY_VALUE(fruit HAVING MAX sold) FROM fruits")
self.validate_identity("SELECT ANY_VALUE(fruit HAVING MIN sold) FROM fruits")
self.validate_all(
"SELECT ANY_VALUE(fruit HAVING MAX sold) FROM Store",
write={
"bigquery": "SELECT ANY_VALUE(fruit HAVING MAX sold) FROM Store",
"duckdb": "SELECT ARG_MAX_NULL(fruit, sold) FROM Store",
},
)
self.validate_all(
"SELECT ANY_VALUE(fruit HAVING MIN sold) FROM Store",
write={
"bigquery": "SELECT ANY_VALUE(fruit HAVING MIN sold) FROM Store",
"duckdb": "SELECT ARG_MIN_NULL(fruit, sold) FROM Store",
},
)
self.validate_all(
"SELECT category, ANY_VALUE(product HAVING MAX price), ANY_VALUE(product HAVING MIN cost), ANY_VALUE(supplier) FROM products GROUP BY category",
write={
"bigquery": "SELECT category, ANY_VALUE(product HAVING MAX price), ANY_VALUE(product HAVING MIN cost), ANY_VALUE(supplier) FROM products GROUP BY category",
"duckdb": "SELECT category, ARG_MAX_NULL(product, price), ARG_MIN_NULL(product, cost), ANY_VALUE(supplier) FROM products GROUP BY category",
},
)
self.validate_all(
'WITH data AS (SELECT "A" AS fruit, 20 AS sold UNION ALL SELECT NULL AS fruit, 25 AS sold) SELECT ANY_VALUE(fruit HAVING MAX sold) FROM data',
write={
"duckdb": "WITH data AS (SELECT 'A' AS fruit, 20 AS sold UNION ALL SELECT NULL AS fruit, 25 AS sold) SELECT ARG_MAX_NULL(fruit, sold) FROM data",
},
)
self.validate_identity("SELECT `project-id`.udfs.func(call.dir)")
self.validate_identity("SELECT CAST(CURRENT_DATE AS STRING FORMAT 'DAY') AS current_day")
self.validate_identity("SAFE_CAST(encrypted_value AS STRING FORMAT 'BASE64')")
Expand Down