1443 words
7 minutes
Searching all columns of a table in Datasette
Searching all columns of a table in Datasette
I came up with this trick today, when I wanted to run a LIKE search against every column in a table.
The trick is to generate a SQL query that does a LIKE search against every column of a table. We can generate that query using another query:
select 'select * from "' || :table || '" where ' || group_concat( '"' || name || '" like ''%'' || :search || ''%''', ' or ' )from pragma_table_info(:table)Here’s what you get when you run that query against the avengers example table from FiveThirtyEight (pretty-printed):
select *from "avengers/avengers"where "URL" like '%' || :search || '%' or "Name/Alias" like '%' || :search || '%' or "Appearances" like '%' || :search || '%' or "Current?" like '%' || :search || '%' or "Gender" like '%' || :search || '%' or "Probationary Introl" like '%' || :search || '%' or "Full/Reserve Avengers Intro" like '%' || :search || '%' or "Year" like '%' || :search || '%' or "Years since joining" like '%' || :search || '%' or "Honorary" like '%' || :search || '%' or "Death1" like '%' || :search || '%' or "Return1" like '%' || :search || '%' or "Death2" like '%' || :search || '%' or "Return2" like '%' || :search || '%' or "Death3" like '%' || :search || '%' or "Return3" like '%' || :search || '%' or "Death4" like '%' || :search || '%' or "Return4" like '%' || :search || '%' or "Death5" like '%' || :search || '%' or "Return5" like '%' || :search || '%' or "Notes" like '%' || :search || '%'Here’s an example search using that generated query.
Same trick for the entire database
Here’s a query that generates a query that searches every column in every table in the database!
with tables as ( select name as table_name from sqlite_master where type = 'table'),queries as ( select 'select ''' || tables.table_name || ''' as _table, rowid from "' || tables.table_name || '" where ' || group_concat( '"' || name || '" like ''%'' || :search || ''%''', ' or ' ) as query from pragma_table_info(tables.table_name), tables group by tables.table_name)select group_concat(query, ' union all ')from queriesI tried this against the FiveThirtyEight database and the query it produced was way beyond the URL length limit for Cloud Run.
Here’s the result if run against latest.datasette.io/fixtures:
select '123_starts_with_digits' as _table, rowidfrom "123_starts_with_digits"where "content" like '%' || :search || '%'union allselect 'Table With Space In Name' as _table, rowidfrom "Table With Space In Name"where "pk" like '%' || :search || '%' or "content" like '%' || :search || '%'union allselect 'attraction_characteristic' as _table, rowidfrom "attraction_characteristic"where "pk" like '%' || :search || '%' or "name" like '%' || :search || '%'union allselect 'binary_data' as _table, rowidfrom "binary_data"where "data" like '%' || :search || '%'union allselect 'complex_foreign_keys' as _table, rowidfrom "complex_foreign_keys"where "pk" like '%' || :search || '%' or "f1" like '%' || :search || '%' or "f2" like '%' || :search || '%' or "f3" like '%' || :search || '%'union allselect 'compound_primary_key' as _table, rowidfrom "compound_primary_key"where "pk1" like '%' || :search || '%' or "pk2" like '%' || :search || '%' or "content" like '%' || :search || '%'union allselect 'compound_three_primary_keys' as _table, rowidfrom "compound_three_primary_keys"where "pk1" like '%' || :search || '%' or "pk2" like '%' || :search || '%' or "pk3" like '%' || :search || '%' or "content" like '%' || :search || '%'union allselect 'custom_foreign_key_label' as _table, rowidfrom "custom_foreign_key_label"where "pk" like '%' || :search || '%' or "foreign_key_with_custom_label" like '%' || :search || '%'union allselect 'facet_cities' as _table, rowidfrom "facet_cities"where "id" like '%' || :search || '%' or "name" like '%' || :search || '%'union allselect 'facetable' as _table, rowidfrom "facetable"where "pk" like '%' || :search || '%' or "created" like '%' || :search || '%' or "planet_int" like '%' || :search || '%' or "on_earth" like '%' || :search || '%' or "state" like '%' || :search || '%' or "city_id" like '%' || :search || '%' or "neighborhood" like '%' || :search || '%' or "tags" like '%' || :search || '%' or "complex_array" like '%' || :search || '%' or "distinct_some_null" like '%' || :search || '%'union allselect 'foreign_key_references' as _table, rowidfrom "foreign_key_references"where "pk" like '%' || :search || '%' or "foreign_key_with_label" like '%' || :search || '%' or "foreign_key_with_blank_label" like '%' || :search || '%' or "foreign_key_with_no_label" like '%' || :search || '%' or "foreign_key_compound_pk1" like '%' || :search || '%' or "foreign_key_compound_pk2" like '%' || :search || '%'union allselect 'infinity' as _table, rowidfrom "infinity"where "value" like '%' || :search || '%'union allselect 'no_primary_key' as _table, rowidfrom "no_primary_key"where "content" like '%' || :search || '%' or "a" like '%' || :search || '%' or "b" like '%' || :search || '%' or "c" like '%' || :search || '%'union allselect 'primary_key_multiple_columns' as _table, rowidfrom "primary_key_multiple_columns"where "id" like '%' || :search || '%' or "content" like '%' || :search || '%' or "content2" like '%' || :search || '%'union allselect 'primary_key_multiple_columns_explicit_label' as _table, rowidfrom "primary_key_multiple_columns_explicit_label"where "id" like '%' || :search || '%' or "content" like '%' || :search || '%' or "content2" like '%' || :search || '%'union allselect 'roadside_attraction_characteristics' as _table, rowidfrom "roadside_attraction_characteristics"where "attraction_id" like '%' || :search || '%' or "characteristic_id" like '%' || :search || '%'union allselect 'roadside_attractions' as _table, rowidfrom "roadside_attractions"where "pk" like '%' || :search || '%' or "name" like '%' || :search || '%' or "address" like '%' || :search || '%' or "latitude" like '%' || :search || '%' or "longitude" like '%' || :search || '%'union allselect 'searchable' as _table, rowidfrom "searchable"where "pk" like '%' || :search || '%' or "text1" like '%' || :search || '%' or "text2" like '%' || :search || '%' or "name with . and spaces" like '%' || :search || '%'union allselect 'searchable_fts' as _table, rowidfrom "searchable_fts"where "text1" like '%' || :search || '%' or "text2" like '%' || :search || '%' or "name with . and spaces" like '%' || :search || '%'union allselect 'searchable_fts_docsize' as _table, rowidfrom "searchable_fts_docsize"where "docid" like '%' || :search || '%' or "size" like '%' || :search || '%'union allselect 'searchable_fts_segdir' as _table, rowidfrom "searchable_fts_segdir"where "level" like '%' || :search || '%' or "idx" like '%' || :search || '%' or "start_block" like '%' || :search || '%' or "leaves_end_block" like '%' || :search || '%' or "end_block" like '%' || :search || '%' or "root" like '%' || :search || '%'union allselect 'searchable_fts_segments' as _table, rowidfrom "searchable_fts_segments"where "blockid" like '%' || :search || '%' or "block" like '%' || :search || '%'union allselect 'searchable_fts_stat' as _table, rowidfrom "searchable_fts_stat"where "id" like '%' || :search || '%' or "value" like '%' || :search || '%'union allselect 'searchable_tags' as _table, rowidfrom "searchable_tags"where "searchable_id" like '%' || :search || '%' or "tag" like '%' || :search || '%'union allselect 'select' as _table, rowidfrom "select"where "group" like '%' || :search || '%' or "having" like '%' || :search || '%' or "and" like '%' || :search || '%' or "json" like '%' || :search || '%'union allselect 'simple_primary_key' as _table, rowidfrom "simple_primary_key"where "id" like '%' || :search || '%' or "content" like '%' || :search || '%'union allselect 'sortable' as _table, rowidfrom "sortable"where "pk1" like '%' || :search || '%' or "pk2" like '%' || :search || '%' or "content" like '%' || :search || '%' or "sortable" like '%' || :search || '%' or "sortable_with_nulls" like '%' || :search || '%' or "sortable_with_nulls_2" like '%' || :search || '%' or "text" like '%' || :search || '%'union allselect 'table/with/slashes.csv' as _table, rowidfrom "table/with/slashes.csv"where "pk" like '%' || :search || '%' or "content" like '%' || :search || '%'union allselect 'tags' as _table, rowidfrom "tags"where "tag" like '%' || :search || '%'union allselect 'units' as _table, rowidfrom "units"where "pk" like '%' || :search || '%' or "distance" like '%' || :search || '%' or "frequency" like '%' || :search || '%' Searching all columns of a table in Datasette
https://mranv.pages.dev/posts/searching-all-columns-of-a-table-in-datasette/