CREATE TABLE в SQL — создание таблиц

Коротко

CREATE TABLE — команда DDL (Data Definition Language) для создания таблиц в базе данных. Определяет столбцы, типы данных, ограничения и связи. Аналитику CREATE TABLE нужен для создания временных таблиц, витрин данных и понимания структуры БД. На собеседованиях спрашивают про типы ограничений, нормализацию и проектирование схемы.

Базовый синтаксис

CREATE TABLE table_name (
    column1  data_type  constraints,
    column2  data_type  constraints,
    ...
    table_constraints
);

Простой пример — таблица пользователей:

CREATE TABLE users (
    user_id    SERIAL PRIMARY KEY,
    username   VARCHAR(50) NOT NULL UNIQUE,
    email      VARCHAR(100) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT NOW()
);
  • SERIAL — автоинкремент (PostgreSQL). В MySQL — INT AUTO_INCREMENT
  • PRIMARY KEY — уникальный идентификатор строки
  • NOT NULL — запрет пустых значений
  • UNIQUE — все значения в столбце уникальны
  • DEFAULT NOW() — значение по умолчанию

Типы данных

Основные типы для PostgreSQL (в других СУБД могут отличаться):

Тип Описание Пример
INTEGER / INT Целое число 42
BIGINT Большое целое 9223372036854775807
SERIAL Автоинкремент (INT) 1, 2, 3...
NUMERIC(p, s) Точное десятичное 99999.99
REAL / FLOAT Приблизительное число 3.14
VARCHAR(n) Строка до n символов 'Иван'
TEXT Строка без ограничения длинный текст
BOOLEAN true / false true
DATE Дата 2025-03-15
TIMESTAMP Дата + время 2025-03-15 14:30:00
JSONB JSON (бинарный) {"key": "value"}
UUID Универсальный ID a0eebc99-9c0b...

Подробнее о типах — в гайде по типам данных SQL.

Ограничения (constraints)

PRIMARY KEY

Уникальный идентификатор каждой строки. Не может быть NULL. Одна таблица — один PRIMARY KEY (может быть составным).

-- Одиночный ключ
CREATE TABLE products (
    product_id SERIAL PRIMARY KEY,
    name       VARCHAR(100) NOT NULL
);

-- Составной ключ
CREATE TABLE order_items (
    order_id   INT,
    product_id INT,
    quantity   INT NOT NULL,
    PRIMARY KEY (order_id, product_id)
);

FOREIGN KEY

Связь между таблицами. Значение в столбце должно существовать в другой таблице.

CREATE TABLE orders (
    order_id   SERIAL PRIMARY KEY,
    user_id    INT NOT NULL REFERENCES users(user_id),
    order_date DATE NOT NULL DEFAULT CURRENT_DATE,
    amount     NUMERIC(10, 2) NOT NULL
);

REFERENCES users(user_id) — каждый order_id должен указывать на существующего пользователя. Попытка вставить order с несуществующим user_id — ошибка.

-- Альтернативный синтаксис с ON DELETE
CREATE TABLE orders (
    order_id   SERIAL PRIMARY KEY,
    user_id    INT NOT NULL,
    amount     NUMERIC(10, 2) NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(user_id)
        ON DELETE CASCADE
        ON UPDATE CASCADE
);
  • ON DELETE CASCADE — удаление пользователя удалит все его заказы
  • ON DELETE SET NULL — user_id станет NULL
  • ON DELETE RESTRICT — запретить удаление, если есть заказы (по умолчанию)

NOT NULL, UNIQUE, DEFAULT, CHECK

CREATE TABLE employees (
    employee_id SERIAL PRIMARY KEY,
    first_name  VARCHAR(50) NOT NULL,
    last_name   VARCHAR(50) NOT NULL,
    email       VARCHAR(100) UNIQUE,
    salary      NUMERIC(10, 2) CHECK (salary > 0),
    department  VARCHAR(50) DEFAULT 'Unassigned',
    hire_date   DATE NOT NULL DEFAULT CURRENT_DATE
);
  • NOT NULL — значение обязательно
  • UNIQUE — без дубликатов (NULL допускается, и несколько NULL не считаются дубликатами в PostgreSQL)
  • CHECK — произвольное условие
  • DEFAULT — значение, если не указано при INSERT

Практические примеры

Схема интернет-магазина

CREATE TABLE categories (
    category_id SERIAL PRIMARY KEY,
    name        VARCHAR(100) NOT NULL UNIQUE,
    parent_id   INT REFERENCES categories(category_id)
);

CREATE TABLE products (
    product_id  SERIAL PRIMARY KEY,
    name        VARCHAR(200) NOT NULL,
    category_id INT REFERENCES categories(category_id),
    price       NUMERIC(10, 2) NOT NULL CHECK (price >= 0),
    is_active   BOOLEAN DEFAULT TRUE,
    created_at  TIMESTAMP DEFAULT NOW()
);

CREATE TABLE orders (
    order_id   SERIAL PRIMARY KEY,
    user_id    INT NOT NULL REFERENCES users(user_id),
    status     VARCHAR(20) DEFAULT 'pending'
                   CHECK (status IN ('pending', 'paid', 'shipped', 'delivered', 'cancelled')),
    total      NUMERIC(12, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE order_items (
    order_id   INT REFERENCES orders(order_id) ON DELETE CASCADE,
    product_id INT REFERENCES products(product_id),
    quantity   INT NOT NULL CHECK (quantity > 0),
    price      NUMERIC(10, 2) NOT NULL,
    PRIMARY KEY (order_id, product_id)
);

Витрина для аналитики

CREATE TABLE daily_metrics AS
SELECT
    DATE(created_at) AS metric_date,
    COUNT(DISTINCT user_id) AS dau,
    COUNT(*) AS events,
    SUM(amount) AS revenue
FROM events
GROUP BY DATE(created_at);

CREATE TABLE ... AS SELECT — создаёт таблицу и заполняет результатом запроса. Удобно для витрин и материализованных отчётов.

Временная таблица

CREATE TEMP TABLE active_users AS
SELECT user_id, COUNT(*) AS sessions
FROM user_sessions
WHERE session_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY user_id
HAVING COUNT(*) >= 5;

Временная таблица существует только в текущей сессии и автоматически удаляется при отключении.

IF NOT EXISTS

CREATE TABLE IF NOT EXISTS users (
    user_id SERIAL PRIMARY KEY,
    username VARCHAR(50) NOT NULL
);

Если таблица уже существует — команда ничего не сделает вместо ошибки. Полезно в скриптах миграций.

ALTER TABLE — изменение структуры

После создания таблицы структуру можно менять:

-- Добавить столбец
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- Удалить столбец
ALTER TABLE users DROP COLUMN phone;

-- Добавить ограничение
ALTER TABLE users ADD CONSTRAINT email_check
    CHECK (email LIKE '%@%');

-- Изменить тип столбца
ALTER TABLE users ALTER COLUMN username TYPE VARCHAR(100);

-- Добавить NOT NULL
ALTER TABLE users ALTER COLUMN email SET NOT NULL;

-- Переименовать столбец
ALTER TABLE users RENAME COLUMN username TO login;

DROP TABLE — удаление таблицы

-- Удалить таблицу
DROP TABLE order_items;

-- Удалить если существует (без ошибки)
DROP TABLE IF EXISTS order_items;

-- Удалить вместе с зависимыми таблицами
DROP TABLE users CASCADE;

CASCADE удалит все внешние ключи и зависимые объекты. Используйте с осторожностью.

Вопросы с собеседований

-- Что такое PRIMARY KEY? -- Ограничение, гарантирующее уникальность и NOT NULL для столбца (или комбинации столбцов). Каждая таблица может иметь только один PRIMARY KEY. Создаёт уникальный индекс.

-- Чем отличается UNIQUE от PRIMARY KEY? -- PRIMARY KEY = UNIQUE + NOT NULL, и он один на таблицу. UNIQUE допускает NULL (в PostgreSQL) и может быть несколько.

-- Что такое FOREIGN KEY? -- Ограничение ссылочной целостности: значение в столбце должно существовать в другой таблице. Обеспечивает связь между таблицами и предотвращает «висячие» ссылки.

-- Когда аналитику нужен CREATE TABLE? -- Создание временных таблиц для сложных расчётов, витрин данных, промежуточных таблиц в ETL, тестовых данных. Также важно для понимания схемы БД и проектирования хранилища.

-- Чем отличается VARCHAR от TEXT? -- VARCHAR(n) ограничивает длину строки. TEXT — без ограничения. В PostgreSQL производительность одинаковая. VARCHAR полезен для валидации (не хранить email длиннее 100 символов).


Потренируйтесь решать задачи — откройте тренажёр с 1500+ вопросами для подготовки к собеседованиям аналитиков.

FAQ

CREATE TABLE vs CREATE TEMP TABLE — в чём разница?

CREATE TABLE создаёт постоянную таблицу, которая остаётся после завершения сессии. CREATE TEMP TABLE — временную, которая живёт только до конца сессии и не видна другим пользователям.

Как скопировать структуру таблицы без данных?

CREATE TABLE new_table (LIKE old_table INCLUDING ALL) — скопирует столбцы, типы, ограничения, индексы. Без INCLUDING ALL — только столбцы и типы.

Нужно ли аналитику знать нормализацию?

Да. Понимание нормальных форм помогает проектировать схемы без аномалий и писать правильные JOIN. На собеседованиях часто просят спроектировать схему для магазина, блога или сервиса.

Как тренироваться

Задачи на CREATE TABLE, DDL и проектирование схемы — в тренажёре Карьерник. Больше вопросов по всем темам — в разделе с примерами.