Repository navigation
Conversation
Without NULLS FIRST or NULLS LAST, NULL sorts as the largest value: last for ASC, first for DESC. A mapping table lists which engines need the explicit clause to match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| RANK() OVER (ORDER BY revenue DESC NULLS LAST) | ||
| ``` | ||
|
|
||
| Without `NULLS FIRST` or `NULLS LAST`, NULL sorts as the largest value: last for `ASC`, first for `DESC`. Implementations MUST produce this order whatever the native default of the engine; see [Window ORDER BY NULL Placement](#window-order-by-null-placement). |
There was a problem hiding this comment.
Just a note: the MUST can't be met on engines with no NULLS FIRST/LAST syntax, such as MySQL/MariaDB and SQL Server (even if I know there are not the first target candidates 😄 ).
Both treat NULL as smallest, so ASC puts NULL first, the opposite of the Ossie default. Following the MUST there needs a rewrite like ORDER BY expr IS NULL, expr.
Maybe we could make the spec either describe that rewrite or say such items may be reported as unsupported? Otherwise conformance on those dialects is undefined.
There was a problem hiding this comment.
Good catch. The new section now covers engines without the clause: a leading CASE WHEN order_expr IS NULL THEN 1 ELSE 0 END key. It is ascending for NULLs last and descending for NULLs first. CASE is the form SQLGlot writes for both MySQL and T-SQL, so one rule covers both.
|
|
||
| Sigma's table-calculation functions (`RowNumber`, `Rank`, `RunningSum`, `RunningAvg`, `Lag`, `Lead`, etc.) resolve their partition/order context from workbook UI configuration (which pivot/table the calculation is attached to) rather than from arguments passed in the formula text itself. Because that context isn't recoverable from the formula string alone, the Sigma converter (`converters/sigma/`) treats these as untranslatable to ANSI SQL and carries the original Sigma formula through in the `SIGMA` dialect only — see `converters/sigma/LIMITATIONS.md`. | ||
|
|
||
| ### Window ORDER BY NULL Placement |
There was a problem hiding this comment.
Because this ### directly after the Sigma table-calculation note, it reads as a Sigma subsection.
| ### Window ORDER BY NULL Placement | |
| ## Window ORDER BY NULL Placement |
There was a problem hiding this comment.
Applied: it is now its own ## section after the tool mappings.
| | :---- | :---- | :---- | :---- | | ||
| | Snowflake, PostgreSQL | NULLS LAST | NULLS FIRST | nothing | | ||
| | BigQuery, Databricks | NULLS FIRST | NULLS LAST | `ASC NULLS LAST`, `DESC NULLS FIRST` | | ||
| | ClickHouse, DuckDB | NULLS LAST | NULLS LAST | `DESC NULLS FIRST` | |
There was a problem hiding this comment.
Maybe we should add other engines (SQL Server, MySQL/MariaDB, Oracle, Redshift, Trino/Athena, ...).
Oracle and Trino default to NULLs largest like Postgres, so omission is safe there.
MySQL/SQL Server need the workaround.
To be honest, I don't know if we need that, so it's more an open question 😄
There was a problem hiding this comment.
Added Oracle, Redshift, Trino, MySQL and SQL Server, each checked against its current docs. One difference from your note: Trino puts NULLs last in both directions. Its docs say "The default null ordering is NULLS LAST, regardless of the ordering direction" (https://trino.io/docs/current/sql/select.html). I left MariaDB out because I couldn't confirm its syntax from the docs.
| | BigQuery, Databricks | NULLS FIRST | NULLS LAST | `ASC NULLS LAST`, `DESC NULLS FIRST` | | ||
| | ClickHouse, DuckDB | NULLS LAST | NULLS LAST | `DESC NULLS FIRST` | | ||
|
|
||
| Snowflake (`DEFAULT_NULL_ORDERING`) and DuckDB (`default_null_order`) let a session change the native default; an implementation that cannot rely on the setting emits the clause on every `ORDER BY` item. |
There was a problem hiding this comment.
I think this conflicts with the table. The table says Snowflake emits "nothing", but this paragraph says to emit the clause on every time if you can't rely on the session setting. A Snowflake or DuckDB converter that follows the table will silently reorder results under a non-default DEFAULT_NULL_ORDERING or default_null_order.
Maybe we should clearly state one rule, for example "omit only when the implementation controls the session setting, otherwise always emit". Also, the table has no entry for the Clickhouse and BigQuery settings that can change the native default, and it doesn't say whether Postgres is safe to omit because it has no such setting.
There was a problem hiding this comment.
Agreed. The section now has one rule: emit the clause. A default placement may be left out only if the native default already gives it. It also needs a session that can't change that default, or an implementation that sets it. The table no longer says when to omit. PostgreSQL may omit: I found no NULL-ordering setting in its configuration reference. Nor could I find one in ClickHouse (system.settings on 26.9) or the BigQuery query syntax reference. If you know one, I'll add it next to Snowflake and DuckDB.
…n section Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sets where NULLs sort in a window
ORDER BYwhenNULLS FIRSTorNULLS LASTis omitted: as the largest value, last forASCand first forDESC. Follows #577 and closes #498. On dev@ [1], @jbonofre proposed this default and @christianeu-db asked for it as a separate PR and vote.The rule is the Order By default of #246 (
foundational_semantics.md§5.1), so a window and a query order NULLs the same way. A new section after the tool mappings says how to produce it. Engines with the clause emit it. MySQL and SQL Server get a leadingCASEsort key instead. A table lists the native default of each engine. The two examples without the clause are the conformance cases JB asked for. They can move to the compliance suite once #237 lands.Impact on implementations: the Holistics (
sqlrefs.transpile) and Hex converters render Ossie expressions into warehouse SQL through SQLGlot, reading them with the base dialect, which treats NULLs as smallest. With SQLGlot 30.23.0,RANK() OVER (ORDER BY x DESC)comes out asDESC NULLS LASTfor Snowflake and PostgreSQL and unchanged for BigQuery and Databricks, the opposite of this default on all four. Reading with a dialect whoseNULL_ORDERINGisnulls_are_largefixes that. The Databricks converter already keeps windows out of the Ossie dialect. T-027 and D-029 in #237 expectNULLS LASTforDESCand would need to follow [2].[1] https://lists.apache.org/thread/z2jr7q4pllsk5nkzv7d18ro8844n5tgy
[2] #237 (comment)