sqlite3 Command Basics - The Shortest Path to Trying SQL in the Terminal
What you'll be able to do
- Open a database with `sqlite3 gym.db`, create a table, and insert data
- Pick out only the rows you need with `SELECT` / `WHERE` / `ORDER BY` / `LIMIT` / `COUNT(*)`
- Pipe SQL results into `sort` / `uniq` and turn a database back into text with `.dump`
Prerequisites (read these first)
What You'll Learn
- How to create a database as a single file with
sqlite3 - The smallest SQL to make a table, add data, and pick it out with
SELECT - Why the numbers differ between
COUNT(*)andwc -l - How to pipe SQL results into
sort/uniq, and how to turn a database back into text with.dump
Words used here (sorted out first)
- Database: a system that stores data so you can search and count it later. Often written "DB".
- Table: data arranged in rows and columns. It is close to a sheet in Excel.
- Rows and columns: a row runs across a table, a column runs down. They are also called "records" and "fields".
- SQL: the language you use to give orders to a database. Many people read it "S-Q-L" or "sequel". One command written in SQL is also called a "query".
- SQLite and sqlite3: SQLite is the name of the software.
sqlite3is the name of the command that operates it. - CSV: a text file whose values are separated by commas (
,). - PromptA symbol (like $ or #) shown when the shell is waiting for your input.: the mark at the start of a line that says "you can type here". In a normal terminalAn interactive program that reads the commands you type and runs them. the line ends with
$, likeuser@pcname:~$. Do not type the$shown in this article.
Environment
- OS: Ubuntu 24.04 (including WSL). For MacA system-wide access control model enforced by fixed rules (Mandatory Access Control)., see section 2
- Output was checked with
sqlite33.45.1 (the version apt installs on Ubuntu 24.04) - Sources: the official SQLite CLI documentation (https://sqlite.org/cli.html , updated 2026-10-13, describing the 3.54 series) and the release history (https://sqlite.org/changes.html )
- Try the steps in this article on your own computer. The virtual terminal on this site also has
sqlite3, but itsgym.dbholds different data prepared for the lessons (see section 7-1)
1. Why sqlite3?
Conclusion: SQLite needs no server. The whole database is a single file, so you can handle it like any file you see with
ls.
ls?gym.db we will make shows up like this with ls -l.$ ls -l gym.db
-rw-r--r-- 1 user user 8192 Oct 24 02:18 gym.db
There is no gym.db yet, so you can try this ls -l after section 4. The owner name and the date depend on your environment.
2. How Do I Install sqlite3?
Conclusion: On Ubuntu and WSL, install it with
apt. A Mac already has it. On both, check it withsqlite3 --version.
On Ubuntu / Debian-based systems
$ sudo apt update $ sudo apt install sqlite3 $ sqlite3 --version
3.45.1 2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257ccalt1 (64-bit)
sudo runs a command with administrator rights. If it asks for a password, type your own login password. The screen shows nothing as you type, not even *. Type it all the way and press Enter. The first number printed by sqlite3 --version is the version. In this example it is 3.45.1.
On Windows: open Ubuntu in WSL (a way to run Linux inside Windows). Then follow the same apt steps. If you do not have WSL yet, start with WSL2 Introduction.
On a Mac: macOS already comes with sqlite3. Check it with sqlite3 --version. You can try everything in this article with the sqlite3 that ships with macOS.
It is safer to make a practice directoryA container that organizes files. Same idea as a "folder" on Windows or macOS. (a folder) first.
$ mkdir ~/sqlite-practice $ cd ~/sqlite-practice
Every file in this article goes inside it.
3. What Changes When I Start sqlite3?
Conclusion: Starting
sqlite3 gym.dbchanges the prompt tosqlite>. Commands that begin with a dot are orders to sqlite3 itself.
sqlite3.gym.db yet. Is that OK?$ sqlite3 gym.db
SQLite version 3.45.1 2024-01-30 16:01:20 Enter ".help" for usage hints. sqlite>
$ to sqlite>... Dot-commands are orders to sqlite3 itself.These are the five you use first.
| Dot-command | What it does |
|---|---|
.tables |
List the tables |
.schema members |
Show how the members table is defined |
.headers on |
Print the column names on the first line |
.mode column |
Line results up in columns |
.quit |
Leave sqlite3 and go back to $ |
Do not put a semicolon (;) at the end of a dot-command. Always put ; at the end of SQL.
Version 3.54.0 and later show a different prompt (see the 3.54.0 entry in the release history). The example in the official documentation is SQLite-3.54 ex1.db->. What you type is the same.
In the code examples, do not type the leading $ or sqlite>. Type only what comes after it. If you use the copy button, delete the leading sqlite> (or $ ) after pasting, then press Enter.
Sections 4 and 5 continue at the sqlite> prompt. If you stop halfway, leave with .quit and come back with sqlite3 gym.db. The table and its data stay in the file. Do not type the CREATE TABLE and INSERT from section 4 again (doing so adds the same rows again). .headers on and .mode column are cleared, so type those two again when you resume from section 5.
4. How Do I Make a Table and Add Data?
Conclusion:
CREATE TABLEdecides the shape of a table, andINSERTadds data one row at a time. Always end SQL with;.
id (number), name, city (where they live), and age.sqlite> CREATE TABLE members (id INTEGER PRIMARY KEY, name TEXT, city TEXT, age INTEGER);
sqlite> INSERT INTO members (name, city, age) VALUES ('Pip', 'Tokyo', 24);
sqlite> INSERT INTO members (name, city, age) VALUES ('Momo', 'Osaka', 31);
sqlite> INSERT INTO members (name, city, age) VALUES ('Kai', 'Tokyo', 19);If it works, nothing is printed and the next sqlite> appears.
INTEGERmeans a whole number, andTEXTmeans text (a string)- Because of
id INTEGER PRIMARY KEY,idgets the numbers 1, 2, 3 automatically - Put text in single quotes (
'), like'Tokyo'
Check the result with dot-commands.
sqlite> .tables
members
sqlite> .schema members
CREATE TABLE members (id INTEGER PRIMARY KEY, name TEXT, city TEXT, age INTEGER);
.tables is like ls, and .schema is like cat..tables to see table names, and .schema to read how a table is built.If you forget ; and press Enter, the prompt changes to ...>. It means "waiting for the rest". Type just ; and press Enter to run it.
5. How Do I Pick Out Only the Rows I Need?
Conclusion: Narrow with
WHERE, order withORDER BY, and cut withLIMIT. They play the same roles asgrep,sort, andhead.
First, print everything in the table. * means "all columns".
sqlite> SELECT * FROM members;
1|Pip|Tokyo|24 2|Momo|Osaka|31 3|Kai|Tokyo|19
| separators are hard to read. I can't tell which column is which..headers on and .mode column are for. The column names appear and everything lines up.sqlite> .headers on sqlite> .mode column sqlite> SELECT * FROM members;
id name city age -- ---- ----- --- 1 Pip Tokyo 24 2 Momo Osaka 31 3 Kai Tokyo 19
In version 3.53.0 and later, a terminal session shows a boxed table from the start (per https://sqlite.org/climode.html and the 3.53.0 entry in the release history). Even with a newer version, type .headers on and .mode column in this article.
5-1. Narrow rows with WHERE (like grep)
sqlite> SELECT name, age FROM members WHERE city = 'Tokyo';
name age ---- --- Pip 24 Kai 19
Like grep Tokyo, only the rows that match the condition appear.
5-2. Order rows with ORDER BY (like sort)
sqlite> SELECT name, age FROM members ORDER BY age DESC;
name age ---- --- Momo 31 Pip 24 Kai 19
DESC means largest first. It is the same direction as sort -rn. Without DESC, the order is smallest first.
5-3. Cut the count with LIMIT (like head)
sqlite> SELECT name, age FROM members ORDER BY age DESC LIMIT 2;
name age ---- --- Momo 31 Pip 24
Like head -n 2, only the first two rows appear.
6. What Happens When I Count?
Conclusion:
COUNT(*)counts the rows of a table. Write it to CSV and count withwc -l, and the column-name line adds one extra.
sqlite> SELECT COUNT(*) FROM members;
COUNT(*) -------- 3
wc -l too..mode csv for the CSV format, and .once to write "only the next result" to a file.sqlite> .mode csv sqlite> .once members.csv sqlite> SELECT * FROM members; sqlite> .quit $ wc -l members.csv
4 members.csv
.quit brought the prompt back to $, so the last wc -l runs as a normal Linux command.
$ cat members.csv
id,name,city,age 1,Pip,Tokyo,24 2,Momo,Osaka,31 3,Kai,Tokyo,19
id,name,city,age. I turned on .headers on earlier, so the column names were written too.wc -l counts lines in a file, and COUNT(*) counts rows in a table. They count different things.To count without the column-name line, use tail -n +2 (print from line 2 to the end).
$ tail -n +2 members.csv | wc -l
3
Now it matches the 3 from COUNT(*). Settings such as .headers on go back to the defaults when you leave sqlite3.
7. How Do I Pipe SQL Results?
Conclusion: Writing
sqlite3 FILE "SQL"runs it once and exits. The result is plain text, so it pipes straight intosortoruniq.
sqlite3 and leaving with .quit every time is a bit of a hassle.$ sqlite3 gym.db "SELECT city FROM members" | sort | uniq -c
1 Osaka
2 Tokyo
sqlite3 gym.db "SELECT city FROM members"prints the city names one per linesortputs the same cities next to each otheruniq -ccounts identical lines
This form does not use .headers on, so no column-name line appears. According to the official documentation, results come out in "list mode" (separated by |).
7-1. Try interactive mode in the virtual terminal
The state where the sqlite> prompt from section 3 is showing is called "interactive mode". You type one line at a time and see the result right away.
You can also try interactive mode in the virtual terminal on this site. Open the lesson "Count the Members" and type the lines below in order. Do not type the leading $ or sqlite>.
$ sqlite3 gym.db
sqlite> SELECT COUNT(*) FROM members;
(one line with the number of members in the lesson's gym.db)
sqlite> .quit
The gym.db in the virtual terminal is prepared for the lesson, so the count differs from the 3 members in this article. When you count correctly, the lesson shows as complete. The one-shot form from section 7 (sqlite3 gym.db "SELECT COUNT(*) FROM members;") completes it as well. In the virtual terminal, the prompt is sqlite> whatever the version.
8. How Do I Turn a Database Back into Text?
Conclusion:
.dumpturns the whole database into SQL text. Feed that text to sqlite3 and you can rebuild the same database.
> overwrites without asking
If a file with the same name already exists, > erases it and writes again. Unlike a GUI, it does not ask "Do you want to replace it?". The .once in section 6 overwrites in the same way. Before you type it, check with ls that no file has the same name, and try it inside your practice directory.
$ sqlite3 gym.db .dump > backup.sql $ cat backup.sql
PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; CREATE TABLE members (id INTEGER PRIMARY KEY, name TEXT, city TEXT, age INTEGER); INSERT INTO members VALUES(1,'Pip','Tokyo',24); INSERT INTO members VALUES(2,'Momo','Osaka',31); INSERT INTO members VALUES(3,'Kai','Tokyo',19); COMMIT;
CREATE TABLE and INSERT I typed are listed here.BEGIN TRANSACTION and COMMIT run the SQL between them as one unit. The PRAGMA line is a setting that sqlite3 added on its own. You can skip them for now.
$ sqlite3 new.db < backup.sql $ sqlite3 new.db "SELECT * FROM members"
1|Pip|Tokyo|24 2|Momo|Osaka|31 3|Kai|Tokyo|19
< feeds the contents of a file to a command. The SQL in backup.sql ran from top to bottom, and new.db now has the same table.
9. Common Mistakes and Fixes
Conclusion: Most mistakes come from four things: semicolons, quotes, letter case, and file names. If an error appears, read it. If there is no error but the result looks wrong, look at the contents directly with
SELECT *orls -l.
| Symptom | Cause | Check / fix |
|---|---|---|
Parse error: near "sqlite": syntax error |
You copied the leading sqlite> too |
Delete sqlite> and type it again |
The prompt stays at ...> |
The ; at the end of the SQL is missing |
Type just ; and press Enter |
Parse error: no such column: Tokyo |
The text is not in ' quotes |
QuoteWrapping a string in quote marks (' or ") so it is treated as one single value, e.g. one with spaces in it. it, like WHERE city = 'Tokyo' |
WHERE city = 'tokyo' returns nothing |
Text comparison treats upper and lower case as different | Match how it is stored in the table (Tokyo) |
gym.db is missing after starting and quitting at once |
In 3.45.1, the file is not created if you do nothing | Make a table before .quit, then check with ls -l |
The member count went up after table members already exists |
You ran the INSERT lines twice |
Remove them with DELETE FROM members WHERE id > 3;, or make gym.db again |
new.db < backup.sql says table members already exists |
new.db already has the same table |
Feed it to a file with another name (e.g. new2.db) |
The 'tokyo' case returns zero rows without an error. When a result is empty, first run SELECT * FROM members; to see how the values are stored.
10. Mini Exercises: Try It Yourself
Conclusion: Try ordering, counting, and piping with your own hands. The answers are inside the folded sections.
Exercise 1: Order by youngest first
Task: Enter with sqlite3 gym.db and type .headers on and .mode column. Then print every member's name and age, youngest first.
Show hint 1 (direction)
Add a phrase for "ordering" after SELECT. Leave out the word you used for largest-first.
Show hint 2 (command name)
Use ORDER BY age. Do not add DESC.
Show answer
sqlite> SELECT name, age FROM members ORDER BY age;
name age ---- --- Kai 19 Pip 24 Momo 31
Exercise 2: Count the members in Osaka
Task: Count how many members have city set to Osaka, using SQL only.
Show hint 1 (direction)
Combine two things: "counting" and "narrowing by a condition".
Show hint 2 (command name)
Add WHERE city = 'Osaka' to SELECT COUNT(*).
Show answer
sqlite> SELECT COUNT(*) FROM members WHERE city = 'Osaka';
COUNT(*) -------- 1
Exercise 3: Count Tokyo members with a pipe
Task: First, go back to $ with .quit. Then, without entering sqlite3, print the names of the members in Tokyo, and count those lines with a Linux command.
Show hint 1 (direction)
Check that the prompt is $. Use the form that runs sqlite3 once and exits. Pass its result to the command that counts lines.
Show hint 2 (command name)
Add | wc -l after sqlite3 gym.db "SELECT ...".
Show answer
$ sqlite3 gym.db "SELECT name FROM members WHERE city = 'Tokyo'" | wc -l
2
This form prints no column-name line, so the wc -l number is the member count as is.
11. Review
gym.db.CREATE TABLE and added rows with INSERT.WHERE is like grep, ORDER BY like sort, and LIMIT like head. And wc -l was one higher because of the column-name line..dump turns it back into text.Today's 3-Line Summary
- SQLite needs no server, and the database is one file you can see with
ls SELECT/WHERE/ORDER BY/LIMITmatch up withgrep/sort/headCOUNT(*)andwc -lcount different things. Watch the first line of a CSV (the column names)