Skip to content

Schema Reference

Tất cả ví dụ trong docs này dùng schema này — khi áp dụng thực tế, thay tên bảng/column tương ứng.


Cách chạy nhanh — từ file dump

⬇ Download dump-learndb-202606291526.sql

Quan hệ giữa các bảng

text
departments ←── employees (department_id)
employees   ←── employees (manager_id, self-referential)

categories  ←── categories (parent_id, self-referential)
categories  ←── products (category_id)
products    ←── inventory (product_id)
products    ←── order_items (product_id)

users       ←── orders (user_id)
orders      ←── order_items (order_id, order_created_at)
users       ←── events (user_id)

DDL — Cấu trúc từng bảng

HR

sql
CREATE TABLE departments (
  id       serial PRIMARY KEY,
  name     text   NOT NULL,
  budget   numeric(14,2),
  location text
);

CREATE TABLE employees (
  id            bigserial PRIMARY KEY,
  department_id int        REFERENCES departments(id),
  manager_id    bigint     REFERENCES employees(id),   -- self-ref
  full_name     text       NOT NULL,
  email         text       NOT NULL UNIQUE,
  salary        numeric(10,2) NOT NULL,
  job_title     text       NOT NULL,
  hired_at      date       NOT NULL,
  is_active     boolean    NOT NULL DEFAULT true
);

E-Commerce

sql
CREATE TABLE categories (
  id        serial PRIMARY KEY,
  parent_id int    REFERENCES categories(id),           -- self-ref
  name      text   NOT NULL,
  slug      text   NOT NULL UNIQUE
);

CREATE TABLE products (
  id          bigserial     PRIMARY KEY,
  category_id int           REFERENCES categories(id),
  sku         text          NOT NULL UNIQUE,
  name        text          NOT NULL,
  description text,
  price       numeric(12,2) NOT NULL,
  cost        numeric(12,2),
  is_active   boolean       NOT NULL DEFAULT true,
  attributes  jsonb         NOT NULL DEFAULT '{}',  -- GIN index target
  tags        text[]        NOT NULL DEFAULT '{}',  -- GIN index target
  created_at  timestamptz   NOT NULL DEFAULT now(),
  updated_at  timestamptz   NOT NULL DEFAULT now()
);

CREATE TABLE inventory (
  id             bigserial PRIMARY KEY,
  product_id     bigint    NOT NULL REFERENCES products(id),
  warehouse_code text      NOT NULL,
  quantity       int       NOT NULL DEFAULT 0 CHECK (quantity >= 0),
  reserved       int       NOT NULL DEFAULT 0 CHECK (reserved >= 0),
  updated_at     timestamptz NOT NULL DEFAULT now(),
  UNIQUE (product_id, warehouse_code)
);

CREATE TABLE users (
  id         bigserial   PRIMARY KEY,
  email      text        NOT NULL UNIQUE,
  full_name  text        NOT NULL,
  phone      text,
  tier       text        NOT NULL DEFAULT 'standard'
               CHECK (tier IN ('standard', 'silver', 'gold', 'platinum')),
  is_active  boolean     NOT NULL DEFAULT true,
  metadata   jsonb       NOT NULL DEFAULT '{}',
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

-- Partitioned by created_at (quarterly: 2022_q3 → 2025_q2 + default)
CREATE TABLE orders (
  id             bigserial,
  user_id        bigint        NOT NULL,
  status         text          NOT NULL DEFAULT 'pending'
                   CHECK (status IN ('pending','confirmed','processing',
                                     'shipped','delivered','cancelled','refunded')),
  total_amount   numeric(12,2) NOT NULL,
  shipping_fee   numeric(10,2) NOT NULL DEFAULT 0,
  region         text          NOT NULL,
  payment_method text          NOT NULL,
  notes          text,
  created_at     timestamptz   NOT NULL DEFAULT now(),
  updated_at     timestamptz   NOT NULL DEFAULT now(),
  PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);

CREATE TABLE order_items (
  id               bigserial     PRIMARY KEY,
  order_id         bigint        NOT NULL,
  order_created_at timestamptz   NOT NULL,
  product_id       bigint        NOT NULL REFERENCES products(id),
  quantity         int           NOT NULL CHECK (quantity > 0),
  unit_price       numeric(12,2) NOT NULL,
  discount_pct     numeric(5,2)  NOT NULL DEFAULT 0,
  created_at       timestamptz   NOT NULL DEFAULT now(),
  FOREIGN KEY (order_id, order_created_at) REFERENCES orders(id, created_at)
);

Events & Time-series

sql
-- Partitioned by created_at (quarterly: 2024_q1 → 2025_q2 + default)
CREATE TABLE events (
  id          bigserial,
  user_id     bigint,
  session_id  text,
  event_type  text        NOT NULL,
  page        text,
  payload     jsonb       NOT NULL DEFAULT '{}',  -- GIN index target
  ip_address  inet,
  created_at  timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);

-- Flat table (không partition) — dùng cho BRIN và time-series patterns
CREATE TABLE metrics (
  id          bigserial   PRIMARY KEY,
  sensor_id   int         NOT NULL,
  metric_name text        NOT NULL,
  value       numeric(10,4) NOT NULL,
  recorded_at timestamptz NOT NULL            -- insert theo thứ tự → BRIN hiệu quả
);

Ghi chú khi dùng trong project thực

Một số ví dụ dùng table không có trong seed (chỉ để minh họa pattern) — được note -- [generic pattern] trong query.

Trong docsThay bằng
usersBảng user/account của bạn
ordersBảng transaction/order của bạn
productsBảng item/product của bạn
eventsBảng event/log của bạn
metricsBảng time-series của bạn
employeesBảng nhân viên/staff của bạn
user_idFK tương ứng trong bảng của bạn
total_amountColumn amount tương ứng
recorded_atTimestamp column của bạn

Personal notes by thanhlt