You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Aggregate window functions: SUM/AVG/COUNT/COUNT_BIG/MIN/MAX/STDEV/STDEVP/VAR/VARP/CHECKSUM_AGG/APPROX_COUNT_DISTINCT(...) OVER (PARTITION BY ...) with implicit-frame whole-partition default; ORDER BY in OVER and explicit ROWS/RANGE BETWEEN raise NotSupportedException; placement / DISTINCT / STRING_AGG misuse raise Msg 4108 / 10759 / 4113.
`ROW_NUMBER() OVER([PARTITION BY <expr-list>] ORDER BY <expr-list-with-direction>)` only — the single shape EF Core 10 emits for top-N / Skip+Take per group. `RANK` / `DENSE_RANK` / analytic family (`LAG` / `LEAD` / `FIRST_VALUE`) and frame specs (`ROWS BETWEEN`, `RANGE BETWEEN`) aren't modeled — EF Core 10 doesn't emit them from idiomatic LINQ. Result type is `bigint`. ORDER BY is required inside OVER (without it, parse fails — SQL Server raises Msg 4112).
182
+
Two shapes are modeled:
183
+
-`ROW_NUMBER() OVER([PARTITION BY <expr-list>] ORDER BY <expr-list-with-direction>)` — for EF Core 10's top-N / Skip+Take per group. Result type `bigint`. ORDER BY is required inside OVER (parse fails otherwise — SQL Server raises Msg 4112).
184
+
- Aggregate windows `SUM/AVG/COUNT/COUNT_BIG/MIN/MAX/STDEV/STDEVP/VAR/VARP/CHECKSUM_AGG/APPROX_COUNT_DISTINCT(<expr>) OVER ([PARTITION BY <expr-list>])` — implicit-frame whole-partition default only (no ORDER BY in OVER for aggregates). Result types match the plain aggregate forms (probe-confirmed against SQL Server 2025, 2026-05-08): `SUM(int)` stays int (overflow → Msg 8115), `SUM(decimal(p,s))` → `decimal(38,s)`, `AVG(int)` truncates, `AVG(decimal(p,s))` → `decimal(38, max(s,6))`, `COUNT*` → int, `COUNT_BIG`/`APPROX_COUNT_DISTINCT` → bigint, `MIN`/`MAX` preserve input type, `STDEV`/`VAR` family → float. NULL semantics also match plain aggregates: all-NULL partition → NULL except COUNT(col) which returns 0.
183
185
184
-
`WindowExpression` (`Parser/Expressions/WindowExpression.cs`) registers itself in `ParserContext.WindowCollector` like aggregates do with `AggregateCollector`. The executor's `ProjectWindowedRows` buffers post-WHERE tuples, partitions by each window's PARTITION BY keys, sorts each partition by ORDER BY keys, assigns row numbers per partition, then walks the buffer in original order binding per-tuple results before projecting. Combining window functions with GROUP BY / HAVING / aggregates raises `NotSupportedException`.
186
+
`RANK` / `DENSE_RANK` / analytic family (`LAG` / `LEAD` / `FIRST_VALUE`), explicit frame specs (`ROWS BETWEEN`, `RANGE BETWEEN`), and aggregate-window ORDER BY (which would require modeling SQL Server's RANGE-with-tie-grouping default frame) aren't modeled — EF Core 10 doesn't emit them from idiomatic LINQ. The frame keywords parse and raise `NotSupportedException` rather than landing as Msg 102, so users hitting the wall get a diagnostic naming the unsupported feature. `STRING_AGG OVER` raises **Msg 4113** (`"The function 'string_agg' is not a valid windowing function..."`); `COUNT(DISTINCT ...) OVER` (and `SUM(DISTINCT) OVER`) raise **Msg 10759** (`"Use of DISTINCT is not allowed with the OVER clause."`); a windowed function in WHERE / HAVING / GROUP BY / ON raises **Msg 4108** (`"Windowed functions can only appear in the SELECT or ORDER BY clauses."`) — gated parse-time by `ParserContext.AllowsWindowExpressions` toggling around the WHERE / GROUP BY / HAVING parses.
187
+
188
+
`WindowExpression` (`Parser/Expressions/WindowExpression.cs`) carries a `WindowKind` discriminator (`RowNumber` / `Aggregate`) and an `AggregateInfo: AggregateExpression?` slot for the wrapped aggregate when `Aggregate`. The aggregate-OVER parse path runs through `WindowExpression.WrapAggregate`, which is invoked from `Expression.Parse`'s binary loop when an `AggregateExpression` is followed by `OVER`. The wrap method pops the aggregate from `AggregateCollector` (since it's window-evaluated, not group-evaluated) and registers the window in `WindowCollector`. The executor's `ProjectWindowedRows` partitions by each window's PARTITION BY keys; for ROW_NUMBER it sorts each partition and assigns 1..N ranks; for aggregates it builds one `Aggregator` per partition, accumulates across all rows in insertion order, and broadcasts `Result()` to every row. Pre-resolved operand and result types (computed in `BuildSqlProjection` at parse time) are passed through to avoid a runtime column-type resolver. Combining window functions with GROUP BY / HAVING / aggregates in the same SELECT still raises `NotSupportedException`.
185
189
186
190
EF Core 10 always wraps ROW_NUMBER in a derived-table subquery: `SELECT ... FROM (SELECT cols, ROW_NUMBER() OVER(...) AS row FROM T) AS sub WHERE sub.row <= N` (Take) or `WHERE 1 < sub.row AND sub.row <= K` (Skip+Take). The simulator's plain-derived-table-doesn't-see-outer-scope limitation doesn't bite here because the ROW_NUMBER subquery has no outer correlation — its OVER refers only to the inner FROM.
- Window functions other than `ROW_NUMBER`: `RANK` / `DENSE_RANK`, analytic (`LAG` / `LEAD` / `FIRST_VALUE` / `LAST_VALUE`), aggregate-OVER form (`SUM(x) OVER(...)` / `COUNT(*) OVER(...)`), frame specs (`ROWS BETWEEN` / `RANGE BETWEEN`). EF Core 10 doesn't emit any of these from idiomatic LINQ.
277
+
- Window functions other than `ROW_NUMBER` and the aggregate-OVER family (`SUM` / `AVG` / `COUNT` / `COUNT_BIG` / `MIN` / `MAX` / statistical / `CHECKSUM_AGG` / `APPROX_COUNT_DISTINCT`): `RANK` / `DENSE_RANK`, analytic (`LAG` / `LEAD` / `FIRST_VALUE` / `LAST_VALUE`), explicit frame specs (`ROWS BETWEEN` / `RANGE BETWEEN`), and ORDER BY inside OVER for aggregate windows (which would require RANGE-with-tie-grouping default frame fidelity). EF Core 10 doesn't emit any of these from idiomatic LINQ. The frame and ORDER-BY-in-aggregate-OVER paths parse + raise `NotSupportedException` (not silent Msg 102) so users get a diagnostic.
274
278
-`STRING_AGG`'s `WITHIN GROUP (ORDER BY ...)`.
275
279
-`LIKE` with `COLLATE` override (default collation only — case-insensitive Latin1_General-shaped).
276
280
-`CONVERT` / `TRY_CONVERT` style codes other than `0` / `120` / `121` for date-like → string. Other styles raise Msg 281; money / float / binary style codes and `CONVERT(date, str, 103)`-style date parsing not modeled.
0 commit comments