Repository navigation
Column statistics dialog in the column action menu - #3038
Merged
Merged
Conversation
Each column's cog menu (and the mobile column actions dialog) gains a "Column statistics" item, available when the actor has execute-sql on the database. It opens a modal that builds SQL in JavaScript and runs it through /db/-/query.json: - Overview: row, null and distinct counts, plus a breakdown of SQLite storage types when a column mixes them - Numbers: min, max, mean, median, standard deviation, sum, a histogram with "nice" bucket widths, a box plot, percentiles computed with the row_number() window function and linear interpolation, and Tukey outlier counts - Text: length statistics and percentiles, counts of blank, padded, multi-line, numeric-looking and ISO date values, and a by-year/month chart for date columns - Most common values, linking to the table filtered to each value - Every query listed with a link to open it in the SQL editor Statistics respect the table page's current filters, including search, _where and _through, excluding _next pagination. The server sends the filter where clause with typed parameters, which are inlined as SQL literals so numeric filters keep their meaning. A toggle switches between filtered rows and the whole table. Pills at the top of the dialog list every column with its declared type, including columns hidden with _nocol, so the dialog can switch between columns without being reopened. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3038 +/- ##
=====================================
Coverage 0.00% 0.00%
=====================================
Files 78 78
Lines 13483 13520 +37
=====================================
- Misses 13483 13520 +37 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ics-modal-0292e6 # Conflicts: # tests/test_playwright.py
- Internal CTE names (vals, stats, ranked, percentiles, positions, picked, filtered_rows) get a numeric suffix when the table name or the current filter mentions them. Previously a table called "stats", or a filter referencing a table called "positions", failed with a SQLite "circular reference" error. - The numeric and date histograms group by position rather than by the "bucket" alias, which SQLite resolved to the column itself when the column was called "bucket", giving wrong date chart counts. - At most two statistics queries run at once. Queries still waiting when the dialog switches column, switches scope or closes are dropped without being sent; queries already sent hold their slot until they finish, keeping load on the server bounded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Arbitrary SQL query pages and stored (canned) query pages now get the
column statistics dialog too, when the actor can execute SQL. Each
result column gets a cog menu with a "Column statistics" item, and a
"Column statistics" button appears above the results on narrow screens
where the headers are hidden.
The statistics wrap the query in a CTE with an explicit column list:
with query_rows("id", "score", "id_2") as (<query>) select ...
which works for queries with their own WITH clause, ORDER BY or LIMIT
and handles duplicate result column names, which the server makes
unique. Query parameters are inlined as string literals, matching how
the query page binds them. Statistics cover every row the query returns,
with a note when that is more than the page shows. Most common values
link to the SQL editor with the query narrowed to that value.
Not offered for queries using magic parameters (their values can't be
passed back in), write queries, non-SELECT statements or queries that
returned no rows. Pills show the storage type seen in the returned rows,
since query results have no declared types.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ics-modal-0292e6 # Conflicts: # docs/template_context.rst # tests/test_playwright.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Table and query pages no longer load column-stats.js up front. A small inline loader, _column_stats_loader.html, defines a stand-in DatasetteColumnStats whose open() imports the script the first time the dialog is opened, in the same way as the Export data dialog. The script then adds the real open() and the rest of its API to that object. The query page's column cog menus and narrow-screen button move out of column-stats.js into query-column-actions.js, the only script query pages now load eagerly for this feature. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a Column statistics item to each column's cog menu on the table page (and to the mobile "Column actions" dialog). It opens a modal that summarises the column by running aggregate SQL queries built in JavaScript against
/<database>/-/query.json.The item is only offered when the actor has
execute-sqlpermission on the database. In that case the table page data gains anexecuteSqlkey.column-stats.jsis not loaded with the page: a small inline loader (_column_stats_loader.html) imports it the first time the dialog is opened, the same way the Export data dialog loadsexport-dialog.js.Then:
Claude Opus 5.5
What the dialog shows
row_number() over (order by v)and linear interpolation, matchingnumpy.percentileandstatistics.quantiles(method="inclusive")Each section shows its own errors, so one timed-out query doesn't hide the rest. Closing the dialog cancels any queries still running.
Respects the current filters
Statistics cover the rows matching the table page's current filters, including
_search,_whereand_through._nextpagination is excluded, so they cover every matching row, not just the current page.whereclause, its parameters and a readable description asexecuteSql.filter./-/query.jsonbinds every parameter as a string, which would break numeric filters such as?age__gt=40on columns with no declared type.Switching columns
Pills at the top of the dialog list every column with its declared type, from the new
executeSql.columnslist. That includes columns hidden with_nocolandrowidfor tables without a primary key, so you can switch columns without reopening the dialog. The pills follow the ARIA tabs pattern: a single Tab stop, arrow keys and Home/End to move, Enter or Space to switch. The filtered/all-rows choice carries over when switching.SQL query pages
Arbitrary SQL query pages (
/<database>/-/query?sql=) and read-only stored queries get the dialog too. Each result column gets a cog menu with a single "Column statistics" item, and at narrow widths, where headers are hidden, a "Column statistics" button appears above the results. These come from the smallquery-column-actions.js, socolumn-stats.jsitself is still only loaded when the dialog first opens.with query_rows("id", "score", "id_2") as (<query>) select .... This works for queries with their ownwithclause,order by,limitor a trailing comment.idcolumns from a join) are made unique on the server.max_returned_rowsshown on the page, with a note when the two differ.mixedif more than one), since query results have no declared types./-/query.json), write queries, non-SELECT statements, or queries that returned no rows.The data comes from a new
query_page_datatemplate context variable, exposed to JavaScript aswindow._datasetteQueryData.Tests
tests/test_table_html.py:executeSqlis gated onallow_sqltests/test_playwright.py:statistics.quantilesThe full Playwright suite passes in Chromium, and the column statistics tests pass in Firefox and WebKit. In the full pytest suite, a few
tests/test_cli_serve_server.pystartup tests failed under-n auto(a different subset each run). All six pass when that file is run on its own.Known limits
sql_time_limit_ms.🤖 Generated with Claude Code