SQL Introduction

What SQL is, the relational model, and the users/orders/products schema used throughout this section.

What SQL is

SQL (Structured Query Language) is the language used to define, query, and manipulate data stored in a relational database. Every mainstream relational database — MySQL, PostgreSQL, SQL Server, Oracle, SQLite — implements SQL, with a shared core syntax and vendor-specific extensions layered on top. Learning SQL well means learning that shared core first; the vendor-specific tutorials later in this track build on exactly what you learn here.

SQL splits into a few functional groups, though in everyday use most people just call all of it "SQL":

  • DDL (Data Definition Language)CREATE, ALTER, DROP. Defines the structure of the database itself.
  • DML (Data Manipulation Language)SELECT, INSERT, UPDATE, DELETE. Reads and writes the data.
  • DCL (Data Control Language)GRANT, REVOKE. Controls permissions.
  • TCL (Transaction Control Language)COMMIT, ROLLBACK. Controls transaction boundaries.

The relational model

A relational database organizes data into tables (also called relations). Each table has a fixed set of columns (attributes, each with a data type) and holds any number of rows (records, each one instance of that structure).

The power of the relational model isn't any single table — it's that tables reference each other through shared key values, so data doesn't need to be duplicated everywhere it's needed. A users table holds user data once; an orders table refers back to a user by id rather than repeating that user's name and email on every order row.

Two kinds of keys make this work:

  • A primary key uniquely identifies a row within its own table (no two rows share one, and it's never null).
  • A foreign key is a column in one table that refers to a primary key in another, creating an enforced link between the two.

The schema used throughout this section

The rest of the SQL pages in this track query a small, consistent schema: users who place orders for products. Run this once and every later example refers back to it.

SQL
CREATE TABLE users (
    id         INT PRIMARY KEY AUTO_INCREMENT,
    name       VARCHAR(100) NOT NULL,
    email      VARCHAR(255) NOT NULL UNIQUE,
    country    VARCHAR(2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE products (
    id       INT PRIMARY KEY AUTO_INCREMENT,
    name     VARCHAR(150) NOT NULL,
    category VARCHAR(50),
    price    DECIMAL(10,2) NOT NULL,
    stock    INT NOT NULL DEFAULT 0
);

CREATE TABLE orders (
    id         INT PRIMARY KEY AUTO_INCREMENT,
    user_id    INT NOT NULL,
    product_id INT NOT NULL,
    quantity   INT NOT NULL DEFAULT 1,
    status     VARCHAR(20) NOT NULL DEFAULT 'pending',
    order_date DATE NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);

A few things worth noticing in that definition:

  • id INT PRIMARY KEY AUTO_INCREMENT — the database assigns a unique, ever-increasing id automatically; you never supply it on insert.
  • NOT NULL on name and email means those columns can never be left empty — the database rejects the insert instead of silently storing incomplete data.
  • UNIQUE on email prevents two users from registering with the same address, enforced by the database itself rather than trusted to application code.
  • DECIMAL(10,2) for price stores exact decimal values (up to 10 digits total, 2 after the point) — never use a floating-point type for money; the "MySQL" pages in this track cover exactly why.
  • The two FOREIGN KEY constraints mean an orders row can never point at a user_id or product_id that doesn't actually exist — the database enforces referential integrity for you.

With those three tables in place, inserting some data looks like this:

SQL
INSERT INTO users (name, email, country) VALUES
    ('Amara Diallo', 'amara@example.com', 'SN'),
    ('Liam Chen', 'liam@example.com', 'CA');

INSERT INTO products (name, category, price, stock) VALUES
    ('Wireless Mouse', 'Electronics', 24.99, 150),
    ('Mechanical Keyboard', 'Electronics', 89.00, 60);

INSERT INTO orders (user_id, product_id, quantity, status, order_date) VALUES
    (1, 1, 2, 'shipped', '2026-01-15'),
    (1, 2, 1, 'pending', '2026-02-03'),
    (2, 2, 1, 'shipped', '2026-02-10');

Common mistakes

  • Treating SQL keywords as case-sensitive syntax rules — they aren't (select and SELECT behave identically), but writing keywords in UPPERCASE and identifiers in lowercase is the near-universal convention that keeps queries readable.
  • Skipping NOT NULL and foreign key constraints "to keep things simple," then relying on application code to enforce rules the database would enforce for free — and inevitably missing a code path that lets bad data in.
  • Using a floating-point type for money because it "seems like a number." Floating-point can't represent many decimal fractions exactly, which causes rounding errors that compound over many transactions.