Read-only REST access to classic sample databases across two engines —
SQL Server (primary) and MySQL/MariaDB. Every response echoes the exact
sql it ran, so you learn the query behind each call.
No key, no login — make a request with any HTTP client. The fastest way to explore is the interactive playground, which builds these URLs for you.
# List everything available (engines + databases) curl "https://learnsql.cpetoday.com/api/catalog" # Get 5 customers from the Northwind database on SQL Server curl "https://learnsql.cpetoday.com/api/mssql/northwind/Customers?limit=5"
Data endpoints are scoped by engine and database, so one API serves every dataset:
/api/{engine}/{database}/{table}
{engine} — mssql (SQL Server, primary) or mysql (MySQL/MariaDB){database} — one of the databases below (e.g. northwind){table} — a table in that database (case-insensitive)Several sample databases (like Northwind) have table/column names with spaces or slashes —
Order Details, Country/Region. URL-encode spaces as %20
in both the path and query string. The playground does this for you.
SQL Server (mssql) — primary:
MySQL / MariaDB (mysql) — secondary:
This list is live — call
GET /api/catalog for the authoritative set. (These pills update automatically.)
List all engines and their databases.
List every table in a database.
Column names, types, nullability, and primary key for a table.
Rows from a table, with pagination, field selection, and sorting.
A single row by its primary-key value.
COUNT / SUM / AVG / MIN / MAX, optionally grouped by a column.
Inner-join two tables and return the combined rows.
Every table, its columns/PKs and all declared foreign keys in one call (powers the schema explorer).
Older URLs without an engine/database — /api/tables, /api/Customer —
still work and default to the mysql / acme dataset.
/{table}| Parameter | Description | Default |
|---|---|---|
page | Page number (1-based) | 1 |
limit | Rows per page (max 10000) | 1000 |
fields | Comma-separated columns to return | all |
sort | Column to sort by | primary key |
order | ASC or DESC | ASC |
/aggregate| Parameter | Description | Required |
|---|---|---|
operation | count, sum, avg, min, max | yes |
field | Column to aggregate (use * with count) | yes |
group_by | Column to group results by | no |
/join/| Parameter | Description | Required |
|---|---|---|
on | Column with the same name in both tables | one of these |
left + right | Key names when they differ per table (e.g. ?left=Customer&right=Company) | one of these |
fields | Custom select list (use t1./t2. aliases) | no |
limit | Rows to return (max 1000) | no |
The same five requests in three languages — copy, run, tweak.
# 1 · What tables are in Northwind? curl "https://learnsql.cpetoday.com/api/mssql/northwind/tables" # 2 · First 5 customers, only two columns curl "https://learnsql.cpetoday.com/api/mssql/northwind/Customers?limit=5&fields=ID,Company" # 3 · One customer by primary key curl "https://learnsql.cpetoday.com/api/mssql/northwind/Customers/1" # 4 · Count customers by country curl "https://learnsql.cpetoday.com/api/mssql/northwind/Customers/aggregate?operation=count&field=*&group_by=Country/Region" # 5 · Join orders to customers on differently-named keys curl "https://learnsql.cpetoday.com/api/mssql/northwind/Orders/join/Customers?left=Customer&right=Company&limit=10"
import requests BASE = "https://learnsql.cpetoday.com/api" # First 5 customers, two columns r = requests.get(f"{BASE}/mssql/northwind/Customers", params={"limit": 5, "fields": "ID,Company"}) data = r.json() print(data["sql"]) # the exact SQL that ran for row in data["data"]: print(row)
const BASE = "https://learnsql.cpetoday.com/api"; // Count customers by country const url = `${BASE}/mssql/northwind/Customers/aggregate` + `?operation=count&field=*&group_by=Country/Region`; const res = await fetch(url); const data = await res.json(); console.log(data.sql); // learn the SQL console.table(data.results); // [{ group, value }, …]
List responses include the data, pagination metadata, and the SQL that ran:
{
"engine": "mssql",
"database": "northwind",
"table": "Customers",
"data": [ { "ID": 1, "Company": "Alfreds Futterkiste" } ],
"pagination": { "page": 1, "limit": 5, "total": 91, "pages": 19 },
"sql": "SELECT [ID], [Company] FROM [northwind].[Customers] ORDER BY [ID] ASC OFFSET 0 ROWS FETCH NEXT 5 ROWS ONLY"
}
Every data endpoint returns a sql field containing the exact query the API executed
against the real database — bracket-quoted identifiers, schema qualification, engine-specific pagination
and all. It’s the core teaching feature: build a request, then read the SQL you effectively just wrote and
paste it into any SQL client to keep learning.
Errors return JSON with an error message and an HTTP status:
| Status | Meaning |
|---|---|
400 | Bad request — invalid parameter, field, or query |
404 | Unknown engine, database, table, or record |
500 | Server or database connection problem |
{ "error": "Table 'Customerz' doesn't exist" }
Responses are plain JSON over HTTP, so you can consume the API from code or everyday desktop tools:
requests.get(url).json()fetch(url).then(r => r.json())/api/… URLFollow the Excel & ODBC connection guide to pull the sample databases straight into Excel — natively, via ODBC Driver 18, or through this API with Power Query.