Quick answer
- In 1bench
- Right-click the table in the sidebar, choose Import Data, browse to a CSV, JSON, NDJSON or SQL file, and click Import.
- In SQL
- sql
.import --csv new_users.csv new_usersRun it in the sqlite3 shell. It creates the table from the header row; for a table that already exists, add --skip 1 so the header is not imported as a row.
Import visually in 1bench
1bench loads a CSV, JSON, NDJSON or SQL file into a SQLite table from a right-click menu. CSV columns are matched to table columns by header name, so the file does not need an id column or every column in the table.
Prerequisite: download 1bench. Free 7-day trial, no sign-up.
- 1
Open your SQLite file
Connect to your .sqlite or .db file in 1bench and expand it in the sidebar.
- 2
Choose Import Data
Right-click the table and choose Import Data. If the table is already open, the Import button in the bar at the bottom of the window opens the same dialog. Neither is offered for views or on a read-only connection.
- 3
Pick the file
Click Browse and choose the file. The Format menu switches to SQL, NDJSON, CSV or JSON from the file extension, and .jsonl counts as NDJSON.
- 4
Decide what happens to existing rows
Rows are added to the table by default. Tick Clear target table before importing to replace its contents instead. For a SQL file, tick Disable foreign key constraints during import if the file inserts child rows before their parents.
- 5
Import
Click Import. A progress bar counts the rows, Stop import cancels, and a message such as Imported 1,200 rows confirms the result.
- The target table must already exist for CSV and JSON. Create it first in the SQL editor, or import a SQL file that contains its CREATE TABLE statement.
- The first CSV line is always the header, and only the comma is read as a separator. Column order does not matter, and columns left out of the file get their DEFAULT or the next AUTOINCREMENT id. A header name the table does not have stops the import with SQLite's "table users has no column named ..." error.
- An empty CSV field becomes NULL. A quoted empty field ("") stays an empty string in text columns and becomes NULL in other columns. Rows with more or fewer fields than the header are skipped, and the result message says how many.
- Each import runs in one transaction, clearing included. If a row fails or you cancel, the table is left exactly as it was, unlike sqlite3's .import, which keeps every row that worked.
- A SQL file runs as written, inside one transaction. The BEGIN TRANSACTION and COMMIT lines that sqlite3 .dump writes are handled, but dot commands such as .mode are not SQL and make the import fail.
- Importing is not available for a remote SQLite file in Live mode over SSH. Switch the connection to Snapshot mode in its settings and reconnect.
Import with the sqlite3 shell and SQL
is the sqlite3 shell's command for loading a file into a table. With it reads standard CSV, quoted fields with commas inside included, and when the table does not exist it creates one using the first line as column names.
.import --csv new_users.csv new_users
The examples use the table from the 1bench demo database () and this file, :
name,email
Ada Lovelace,[email protected]
"Hopper, Grace",[email protected]
Alan Turing,
Everything below was run on SQLite 3.43.2 and 3.54.1. Where the two behave differently, the section says so.
Import a CSV into a new table
When the target table is missing, creates it from the header and loads the remaining lines. Each column is created without a declared type on 3.54.1 and as TEXT on 3.43.2, and either way every value arrives as text.
sqlite> .import --csv new_users.csv users_import
sqlite> .schema users_import
CREATE TABLE "users_import"(
"name", "email");
That is fine for a quick look at a file, but numbers stay text and sort and compare as text. For real work, create the table with proper types first and import into it, as in the next section.
Import a CSV into an existing table
For a table that already exists, treats every line as data, header included. Add to drop the header, or you get a row whose name is "name" and whose email is "email".
.import --csv --skip 1 new_users.csv users_staging
The file must also have exactly as many columns as the table, in the same order. cannot fill a subset of columns, so loading straight into fails on every line:
new_users.csv:2: expected 4 columns but found 2 - filling the rest with NULL
new_users.csv:2: INSERT failed: datatype mismatch
The datatype mismatch comes from the column, which only takes integers. A CSV with an empty id column fails the same way, because writes the empty field as '' rather than NULL, so the auto-increment never kicks in.
Example: load the file into a staging table, then copy the rows into so and get their defaults.
CREATE TEMP TABLE users_staging (name TEXT, email TEXT);
.import --csv --skip 1 new_users.csv users_staging
INSERT INTO users (name, email)
SELECT name, email FROM users_staging WHERE email <> '';
The drops Alan Turing, whose email is empty. would not have caught that row, since an empty string is not NULL.
Set the separator: TSV, semicolons and pipes
always splits on commas, so a semicolon file imported with it lands in a single column called "name;email". For any other separator, set the mode and separator first and run without .
.mode tabs
.import events.tsv events_raw
.mode csv
.separator ";"
.import export_eu.csv customers_raw
Quote the separator. 3.43 accepts , but 3.54 reads the bare semicolon as the end of the command and answers "Usage: .separator COL ?ROW?". With plus a separator, quoted fields still work, so keeps the semicolon inside the name.
A stray quote in the middle of an unquoted field produces "unescaped " character" warnings. The row is still imported with the quotes kept as text, so check those rows afterwards.
Import from the command line
Every dot command also works as an argument to , which makes imports easy to script.
sqlite3 shop.db ".import --csv --skip 1 new_users.csv users_staging"
reads standard input when the file name is , so you can pipe a download or a decompressed file straight in.
gunzip -c new_users.csv.gz | sqlite3 shop.db ".import --csv /dev/stdin users_import"
Example: load every CSV in a folder into its own table, named after the file.
for f in *.csv; do
sqlite3 shop.db ".import --csv $f ${f%.csv}_raw"
done
prints a summary line such as "Added 3 rows with 0 errors using 4 lines of input" when you want a count. picks an attached database, as in .
Import a SQL file or dump
runs every statement in a SQL file, which is how you load a dump made with . From your own shell, redirecting the file into does the same thing.
sqlite3 restored.db ".read dump.sql"
sqlite3 restored.db < dump.sql
A file starts with and and ends with , so it loads in one go. Run it twice against the same database and you get "Parse error near line 3 of dump.sql: table users already exists" for every table, then "UNIQUE constraint failed: users.id" for every row, because sqlite3 reports each error and moves on to the next statement. Add to stop at the first error instead.
sqlite3 -bail restored.db ".read dump.sql"
Dumps from other databases need editing first. A mysqldump table definition fails with , and every INSERT after it fails with "no such table".
Import JSON
SQLite has no , but turns a JSON array into rows, and the shell's reads the file. pulls a field out as a plain SQL value.
Example: insert users from a file that holds an array of objects, using the current time when is missing.
INSERT INTO users (name, email, created_at)
SELECT value->>'name',
value->>'email',
coalesce(value->>'created_at', datetime('now'))
FROM json_each(readfile('users.json'));
exists only in the sqlite3 shell. From application code, read the file yourself and pass the text as a parameter, as in . The operator needs SQLite 3.38 or later; on older versions use .
Import from Excel
The sqlite3 shell cannot read .xlsx files. In Excel, choose File, Save As, CSV UTF-8, then import the CSV as above. Excel puts a byte order mark at the start of that file, and strips it, so the first column name comes through clean on both versions tested.
.import --csv customers.csv customers_raw
With several sheets, or to keep number types without creating the table by hand, pandas reads the workbook directly. It needs the openpyxl package.
import sqlite3
import pandas as pd
con = sqlite3.connect("shop.db")
df = pd.read_excel("rollout.xlsx", sheet_name="Rollout")
df.to_sql("rollout_xlsx", con, if_exists="replace", index=False)
Import with Python
The standard library's and modules are enough for most imports. wraps the inserts in one transaction, so a failing row rolls back the whole batch and also keeps large loads fast.
import csv
import sqlite3
con = sqlite3.connect("shop.db")
with open("new_users.csv", newline="", encoding="utf-8-sig") as f:
rows = [(r["name"], r["email"]) for r in csv.DictReader(f) if r["email"]]
with con:
con.executemany("INSERT INTO users (name, email) VALUES (?, ?)", rows)
drops the byte order mark Excel adds. The filter skips the row with no email. Turning empty fields into NULL with instead makes the insert fail with , and because of nothing is written.
pandas does the same in one line and infers types: creates INTEGER and REAL columns where the data fits and writes empty cells as NULL.
import sqlite3
import pandas as pd
con = sqlite3.connect("shop.db")
pd.read_csv("new_users.csv").dropna(subset=["email"]).to_sql(
"users", con, if_exists="append", index=False
)
decides what happens when the table exists. The default, , raises "Table 'users' already exists"; inserts only the DataFrame's columns, so and get their defaults; drops the table and recreates it without your primary key, constraints or indexes. A DataFrame column the table does not have fails with "table users has no column named extra".
Import a table from another database file
opens a second SQLite file in the same session, so copying a table between files is a plain or .
ATTACH 'old_shop.db' AS old;
CREATE TABLE users_archive AS SELECT * FROM old.users;
INSERT OR IGNORE INTO users SELECT * FROM old.users;
copies the columns and their rough types (, ) but not the primary key, AUTOINCREMENT, UNIQUE or DEFAULT clauses. To keep those, create the table with its full definition first and use . A plain of rows whose ids already exist fails with "UNIQUE constraint failed: users.id"; skips them, and overwrites them.
NULLs and column types
never writes NULL. An empty field is stored as an empty string, even in an INTEGER or REAL column, where it stays text because '' cannot be converted to a number.
Example: has an empty for one feature. Import it into a typed table, then turn the empty strings into NULL.
CREATE TABLE rollout_typed (feature_key TEXT, enabled INTEGER, rollout_percentage REAL);
.import --csv --skip 1 rollout.csv rollout_typed
UPDATE rollout_typed SET rollout_percentage = NULL WHERE rollout_percentage = '';
The typed table matters. In the same file imported with no table created first, returns 3 on 3.54 (text is always greater than a number in a column with no type) and 0 on 3.43 (the TEXT column compares '100' to '50' as strings). The right answer, 1, only comes from the REAL column. If you have already imported into text columns, fixes a single query, and a new typed table plus fixes the data.