A lightweight, shell-based database management system that stores all data as plain CSV files. No SQL, no setup, no external database server — just Python and a clean command language.
- Plain CSV storage — every table is a
.csvfile you can open in any spreadsheet app - Rich query language — filtering, sorting, limiting, joining, and aggregates
- Coloured output — green for success, red for errors, yellow for warnings, cyan for info
- Robust error handling — every command validates input and reports problems clearly
- No dependencies beyond Python — only
coloramaandtabulaterequired
git clone [https://github.com/ciada-3301/NanoDB]
cd nano-db
pip install colorama tabulate
python NanoDB.py>>> create employees(id,name,age,city,department,salary)
>>> use employees
>>> add record((1,alice,30,london,engineering,85000),(2,bob,25,paris,marketing,45000))
>>> get all
>>> get all where(city=london)
>>> exit
create <table>(field1,field2,...)
>>> create employees(id,name,age,city,department,salary)
>>> create products(product_id,name,category,price,stock)
Table and field names may only contain lowercase letters, digits, and underscores.
use <table>
>>> use employees
The active table name is shown in the prompt. Most commands operate on the active table by default.
current
>>> current
ℹ Database : employees
ℹ Fields : id, name, age, city, department, salary
ℹ Rows : 8
list
>>> list
ℹ Databases found: 3
► employees (current)
• projects
• archive
add record(<v1>,<v2>,...) # single row
add record((<v1>,<v2>),(<v3>,<v4>),...) # multiple rows
>>> add record(1,alice,30,london,engineering,85000)
>>> add record((1,alice,30,london,engineering,85000),(2,bob,17,paris,marketing,45000))
All records are validated before any are written — a mismatch on one record cancels all of them.
add column(<col1>,<col2>,...)
>>> add column(bonus)
>>> add column(bonus,notes,rating)
New columns are added with empty values for all existing rows.
delete database <table>
>>> delete database archive
⚠️ Irreversible. Consider usingcopyto back up first.
delete column(<column>)
>>> delete column(bonus)
delete where(<conditions>)
>>> delete where(city=paris)
>>> delete where(department=hr and city=berlin)
change <field>=<value> where(<conditions>)
>>> change city=berlin where(name=alice)
>>> change salary=90000 where(department=engineering and city=london)
Only one field can be updated per command.
rename database <old> to <new>
>>> rename database employees to staff
If the renamed table is currently selected, the prompt updates automatically.
rename column(<old> to <new>)
rename column(<old> to <new>) in <table>
>>> rename column(salary to income)
>>> rename column(bonus to reward) in employees
copy <table> to <new_table>
>>> copy employees to employees_backup
Useful before destructive operations like
delete whereorchange.
get all
get all from (<table>)
get (<field1>,<field2>,...) from (<table>)
get all where(<conditions>)
get all sort(<column> asc|desc) limit(<n>)
get all from (<t1>,<t2>) join(<t1.col>=<t2.col>)
get (count(<col>),sum(<col>),avg(<col>),min(<col>),max(<col>))
>>> get all
>>> get all from (employees)
>>> get (name,salary) from (employees)
>>> get all where(city=london)
>>> get all where(city=london or city=berlin)
>>> get all where(not department=hr)
>>> get all where(name~ali)
>>> get all sort(salary desc) limit(5)
>>> get all from (projects,employees) join(projects.empid=employees.id)
>>> get (count(id),avg(salary),min(salary),max(salary)) from (employees)
from()is optional when a table is already selected. Bothfrom(db)andfrom (db)spacing styles are supported.
export <newdb>(<table1.col>=<table2.col>) # join two tables
export <newdb>(<table.col>=<value>) # filter one table
>>> export merged(projects.empid=employees.id)
>>> export londonteam(employees.city=london)
| Operator | Meaning | Example |
|---|---|---|
= |
Exact match | where(city=london) |
!= |
Not equal | where(city!=paris) |
~ |
Substring match (case-insensitive) | where(name~ali) |
and |
Both conditions must be true | where(city=london and department=engineering) |
or |
Either condition must be true | where(city=london or city=berlin) |
not |
Negates the following condition | where(not age=17) |
Conditions can be combined freely:
>>> get all where(city=london and not name~ca)
>>> get all where(not department=hr or salary!=45000)
| Function | Description |
|---|---|
count(col) |
Number of rows |
sum(col) |
Sum of numeric values |
avg(col) |
Average of numeric values |
min(col) |
Minimum numeric value |
max(col) |
Maximum numeric value |
>>> get (count(id),avg(salary),min(salary),max(salary)) from (employees)
>>> get (count(id),avg(salary)) from (employees) where(department=engineering)
Safe bulk update
>>> copy employees to employees_backup
>>> change salary=90000 where(department=engineering)
>>> get all where(department=engineering)
>>> delete database employees_backup
Join two tables
>>> get all from (projects,employees) join(projects.empid=employees.id)
Export a filtered subset
>>> export londoneng(employees.city=london)
>>> use londoneng
>>> get all where(department=engineering)
Aggregate by running a filter first
>>> get (count(id),avg(salary)) from (employees) where(department=engineering)
| Colour | Meaning |
|---|---|
🟢 Green ✔ |
Success — operation completed |
🔴 Red ✖ |
Error — invalid input, missing table, etc. |
🟡 Yellow ⚠ |
Warning — 0 rows matched, field skipped |
🔵 Cyan ℹ |
Info — table details, list output |
nano-db/
├── db_shell.py # main shell — run this
└── README.md
All tables are stored as .csv files in the same directory as db_shell.py.
- Python 3.7+
colorama— terminal colourstabulate— grid table output
pip install colorama tabulateFree to use but with proper credits to source