Skip to content
Open
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
2 changes: 1 addition & 1 deletion mimic-iv/concepts_duckdb/demographics/icustay_hourly.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ WITH all_hours AS (
THEN it.intime_hr
ELSE DATE_TRUNC('HOUR', CAST(it.intime_hr AS TIMESTAMP)) + INTERVAL '1' HOUR
END AS endtime,
GENERATE_SERIES(-24, CAST(CEIL(DATE_DIFF('HOUR', it.intime_hr, it.outtime_hr)) AS INT)) AS hrs
(SELECT list(g) FROM generate_series(-24, CAST(CEIL(DATE_DIFF('HOUR', it.intime_hr, it.outtime_hr)) AS INT)) AS t(g)) AS hrs
FROM mimiciv_derived.icustay_times AS it
)
SELECT
Expand Down
15 changes: 15 additions & 0 deletions src/mimic_utils/sqlglot_dialects/duckdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,21 @@
- ``NUMERIC`` is ``DECIMAL(38, 9)``, but DuckDB's bare ``DECIMAL`` defaults
to ``DECIMAL(18, 3)``, which silently rounds values to three decimal places
(e.g. ``CAST(0.0255 AS NUMERIC)`` becomes ``0.026`` before any explicit ``ROUND``).
- ``GENERATE_ARRAY`` must remain a LIST (for later ``UNNEST``). Native sqlglot
emits ``GENERATE_SERIES``, which is a set-returning function and breaks
``UNNEST(hrs)`` with ``unnest(integer)`` / type errors (#1736).
"""
from sqlglot import exp
from sqlglot.dialects.duckdb import DuckDB


def _generate_array_sql(self: DuckDB.Generator, expression: exp.Expression) -> str:
start = self.sql(expression, "start")
end = self.sql(expression, "end")
# Inclusive list, matching BigQuery GENERATE_ARRAY / Postgres ARRAY(GENERATE_SERIES).
return f"(SELECT list(g) FROM generate_series({start}, {end}) AS t(g))"


class MimicDuckDB(DuckDB):
class Generator(DuckDB.Generator):
def datatype_sql(self, expression: exp.DataType) -> str:
Expand All @@ -16,3 +26,8 @@ def datatype_sql(self, expression: exp.DataType) -> str:
if expression.this == exp.DataType.Type.DECIMAL and not expression.expressions:
return "DECIMAL(38, 9)"
return super().datatype_sql(expression)

TRANSFORMS = {
**DuckDB.Generator.TRANSFORMS,
exp.GenerateSeries: _generate_array_sql,
}
3 changes: 3 additions & 0 deletions tests/test_transpile.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ def t(bq: str, dialect: str) -> str:
# GENERATE_ARRAY -> ARRAY(SELECT ... GENERATE_SERIES) (postgres)
("generate_array_pg", "SELECT GENERATE_ARRAY(-24, 5) AS hrs FROM t", "postgres",
"SELECT ARRAY(SELECT * FROM GENERATE_SERIES(-24, 5)) AS hrs FROM t"),
# GENERATE_ARRAY -> list via generate_series (duckdb); must stay list for UNNEST
("generate_array_duckdb", "SELECT GENERATE_ARRAY(-24, 5) AS hrs FROM t", "duckdb",
"SELECT (SELECT list(g) FROM generate_series(-24, 5) AS t(g)) AS hrs FROM t"),

# handled natively by sqlglot 30.x (regression guards)
("datetime_date_pg", "SELECT DATETIME(me.chartdate) FROM t me", "postgres",
Expand Down
Loading