csvsql: Run a SQL query over a csv file

#!/usr/bin/env bash
help_text="
NAME
    csvsql - Run a SQL query over a csv file

USAGE
    csvsql [options] <csv_filename> [<sql_query (in quotes)>]

OPTIONS
    -d, --database
        Specify the database file to use with sqlite3. If not provided, an in-memory database is used.

    -h, --help
        Show this help message and exit

    -f, --file
        Specify a file containing a SQL query to run over the csv file.

    -n, --no-query
        Do not run any SQL query over the CSV file. For use with -d|--database to load a csv to a database.

    -s, --silent
        Suppress warnings about unexpected columns in the CSV file.

DESCRIPTION
    A script to run a SQL query over data in a csv file using sqlite3.

    If no SQL query is provided, Sqlite3 will be run in interactive mode.

    The table to query has the name 't'

AUTHOR
    mjnurse.github.io - 2026
"

help_line="Run a SQL query over a csv file"
web_desc_line="Run a SQL query over a csv file"

if [[ "$1" == "" ]]; then
  echo "Usage: csvsql <csv_filename> [<sql_query (in quotes)>]"
  echo "Try csvsql -h for more information"
  exit
fi

database=":memory:"
silent=false
sql_file=""
no_query=false
while [[ "$1" != "" ]]; do
    case $1 in
        -d|--database)
            shift
            database="$1"
            ;;
        -f|--file)
            shift
            sql_file="$1"
            ;;
        -h|--help)
            echo "$help_text"
            exit
            ;;
        -s|--silent)
            silent=true
            ;;
        -n|--no-query)
            no_query=true
            ;;
        ?*)
            break
            ;;
    esac
    shift
done

filter=""
if [[ $silent == true ]]; then
    filter="
        /expected.*columns but found/d;
    "
fi
if [[ "$sql_file" != "" ]]; then
    # Run the SQL query from the file
    sqlite3 "$database" -cmd ".mode csv" -cmd ".import $1 t" \
            -cmd ".mode column" -header < "$sql_file" 2>&1 | sed -e "$filter"
elif [[ "$no_query" == true ]]; then
    # Do not run any SQL query over the CSV file
    sqlite3 "$database" -cmd ".mode csv" -cmd ".import $1 t" \
            -cmd ".mode column" -header ".q" 2>&1
elif [[ "$2" == "" ]]; then
    # Run sqlite3 in interactive mode
    sqlite3 "$database" -cmd ".mode csv" -cmd ".import $1 t" \
            -cmd ".mode column" -header 2>&1
else
    # Run the SQL query from the command line
    sqlite3 "$database" -cmd ".mode csv" -cmd ".import $1 t" \
            -cmd ".mode column" -header "$2" 2>&1 | sed -e "$filter"
fi