taozhi8833998 / taozhi8833998/node-sql-parser

SQLite: OVER () and OVER (ORDER BY ...) rejected — PARTITION BY treated as required

Open
#2,680 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PEG.js
Stars
1k
Forks
244
PR merge metrics
No merged PRs in 30d

Description

Version

node-sql-parser@5.4.0

Summary

In the SQLite dialect, PARTITION BY is required inside OVER (...). SQLite makes every clause of a window definition optional, so OVER () and OVER (ORDER BY ...) are valid SQLite that the parser rejects.

Every other dialect I tried parses the bare form, so this looks like an oversight in the SQLite grammar rather than an intentional restriction.

Reproduction
const { Parser } = require('node-sql-parser')
const p = new Parser()

p.astify('SELECT SUM(b) OVER () FROM t', { database: 'SQLite' })
// Error: Expected "#", "--", "/*", "PARTITION", or [ \t\n\r] but ")" found.

p.astify('SELECT SUM(b) OVER (ORDER BY d) FROM t', { database: 'SQLite' })
// Error: Expected "#", "--", "/*", "PARTITION", or [ \t\n\r] but "O" found.

p.astify('SELECT SUM(b) OVER (PARTITION BY c) FROM t', { database: 'SQLite' })
// OK

The function does not matter — ROW_NUMBER(), RANK(), LAG() and COUNT(*) all behave the same way: fine with PARTITION BY, rejected without it.

Expected

All three should parse. Per the SQLite window-function grammar, window-defn is:

( [base-window-name] [PARTITION BY expr, ...] [ORDER BY term, ...] [frame-spec] )

— every clause optional, including an entirely empty ().

Confirmed against the engine: SQLite 3.53.4 (via better-sqlite3 13.x) executes all three forms correctly.

Dialect comparison

Same two queries, partition = OVER (PARTITION BY c), bare = OVER ():

SQLite        partition:OK  bare:REJECT
MySQL         partition:OK  bare:OK
PostgreSQL    partition:OK  bare:OK
BigQuery      partition:OK  bare:OK
TransactSQL   partition:OK  bare:OK
MariaDB       partition:OK  bare:OK
Hive          partition:OK  bare:OK
Snowflake     partition:OK  bare:OK
Impact

OVER () is how you get a grand total alongside a grouped aggregate in one pass:

SELECT c, COUNT(*) AS n,
       ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) AS pct
FROM t GROUP BY c

Without it, callers issue a second query for the total. There is a workaround — OVER (PARTITION BY NULL) parses and is semantically identical — but it is obscure enough that anyone hitting this will more likely conclude window functions are unsupported in the SQLite dialect and stop using them.

Related SQLite gaps found alongside this

Same pattern — valid SQLite that 5.4.0's SQLite dialect rejects, all verified as executing correctly on SQLite 3.53.4. Listing them here in case they share a cause; happy to split them into separate issues if you would prefer:

  • SELECT COUNT(*) FILTER (WHERE b > 1) FROM taggregate FILTER clause
  • SELECT a FROM t ORDER BY b NULLS LAST
  • SELECT SUM(b) OVER (PARTITION BY a ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t — frame spec
  • SELECT SUM(b) OVER w FROM t WINDOW w AS (PARTITION BY a) — named window

For contrast, these all parse fine in the SQLite dialect: CTEs, CASE WHEN, UNION, subqueries in FROM, EXISTS, CAST, COALESCE, strftime, date(), GROUP_CONCAT, IIF, LIMIT/OFFSET, HAVING, and joins.

I am happy to put together a PR for the PARTITION BY fix if that would help — it looks like making the clause optional in the SQLite window rule.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the SQLite window-function grammar entry point and run the three SQL reproductions from the issue. Done means the parser accepts OVER (), OVER (ORDER BY d), and OVER (PARTITION BY c) for SQLite without regressing the existing partitioned form.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, sql
Domain
databases, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.