Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Создание таблицы в SQL
Это базовый навык, но покажу как делать правильно с точки зрения production систем и best practices.
Базовый синтаксис
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Детальное объяснение
1. PRIMARY KEY
Основной ключ — уникальный идентификатор строки.
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT -- Автоинкремент
);
-- Или UUID (рекомендую для распределённых систем)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid() -- PostgreSQL
);
-- Или составной ключ
CREATE TABLE user_roles (
user_id INT NOT NULL,
role_id INT NOT NULL,
PRIMARY KEY (user_id, role_id)
);
2. Типы данных
CREATE TABLE products (
-- Числа
id INT, -- Integer
quantity BIGINT, -- Long
price DECIMAL(10, 2), -- Decimal для денег (10 цифр, 2 после запятой)
rating FLOAT, -- Для обычных float
-- Строки
name VARCHAR(100), -- Переменная длина до 100
description TEXT, -- Большой текст
-- Время
created_at TIMESTAMP, -- Дата и время
created_date DATE, -- Только дата
updated_at TIMESTAMPTZ, -- Timestamp с timezone (PostgreSQL)
-- Boolean
is_active BOOLEAN, -- true/false
-- JSON (современные БД)
metadata JSON, -- Хранит JSON документ
attributes JSONB -- Binary JSON (PostgreSQL, быстрее)
);
3. Constraints (ограничения)
CREATE TABLE users (
id INT PRIMARY KEY,
-- NOT NULL — обязательное поле
email VARCHAR(100) NOT NULL,
-- UNIQUE — уникальное значение
username VARCHAR(50) UNIQUE NOT NULL,
-- DEFAULT — значение по умолчанию
status VARCHAR(20) DEFAULT 'active',
-- CHECK — проверка значения
age INT CHECK (age >= 18),
-- FOREIGN KEY — связь с другой таблицей
department_id INT NOT NULL,
FOREIGN KEY (department_id) REFERENCES departments(id)
ON DELETE CASCADE -- Удалить пользователя если удалили отдел
ON UPDATE CASCADE -- Обновить если обновился отдел
);
Production-ready таблица
CREATE TABLE users (
-- ID
id BIGSERIAL PRIMARY KEY, -- 64-bit автоинкремент
-- Основные данные
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
-- Профиль
first_name VARCHAR(100),
last_name VARCHAR(100),
phone VARCHAR(20),
-- Статус
status VARCHAR(20) NOT NULL DEFAULT 'active', -- active, inactive, banned
is_email_verified BOOLEAN DEFAULT false,
-- Timestamps
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMPTZ, -- Для soft delete
-- Контроль целостности
version INT DEFAULT 0, -- Для оптимистичного locking
-- Индексы
CONSTRAINT check_email_format CHECK (email ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$')
);
-- Индексы для быстрого поиска
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_status ON users(status);
CREATE INDEX idx_users_created_at ON users(created_at DESC);
-- Составной индекс для частых queries
CREATE INDEX idx_users_status_created ON users(status, created_at DESC);
Связанные таблицы
-- Отделы
CREATE TABLE departments (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL UNIQUE,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
-- Пользователи (с внешним ключом)
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
department_id BIGINT NOT NULL,
FOREIGN KEY (department_id) REFERENCES departments(id) ON DELETE CASCADE
);
-- Роли (many-to-many)
CREATE TABLE roles (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE
);
-- Связующая таблица
CREATE TABLE user_roles (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
assigned_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);
PostgreSQL специфичные особенности
CREATE TABLE users (
-- UUID вместо int
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Enum типы
status user_status NOT NULL DEFAULT 'active', -- Создать тип сначала
-- Array
tags TEXT[] DEFAULT ARRAY[],
-- JSONB для metadata
metadata JSONB DEFAULT '{}'::JSONB,
-- Full text search
search_vector tsvector GENERATED ALWAYS AS (
to_tsvector('russian', name || ' ' || description)
) STORED,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_search ON users USING GIN(search_vector);
Миграции в приложении (Flyway/Liquibase)
// V1__create_users_table.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
version INT DEFAULT 0
);
// V2__add_phone_to_users.sql (добавляем колонку)
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
// V3__add_index.sql (добавляем индекс)
CREATE INDEX idx_users_email ON users(email);
Best Practices
- Всегда используй PRIMARY KEY
✓ CREATE TABLE users (id INT PRIMARY KEY, ...)
✗ CREATE TABLE users (username VARCHAR(50), ...) -- Ошибка!
- Используй BIGINT для ID в больших системах
✓ id BIGINT
✗ id INT -- Переполнится при > 2.1 миллиарда строк
- Всегда ставь NOT NULL если есть смысл
✓ email VARCHAR(100) NOT NULL
✗ email VARCHAR(100) -- NULL это не ошибка
- UNIQUE для уникальных полей
✓ username VARCHAR(50) UNIQUE NOT NULL
✗ username VARCHAR(50) -- Могут быть дубликаты
- Timestamps для audit trail
✓ created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
✓ updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
✗ -- Без них нельзя отследить когда менялись данные
- FOREIGN KEY для целостности
✓ department_id INT REFERENCES departments(id) ON DELETE CASCADE
✗ department_id INT -- Может быть несуществующий ID
- Индексы для поиска
✓ CREATE INDEX idx_email ON users(email);
✗ -- Без индекса FULL TABLE SCAN при каждом поиске
- Для денег используй DECIMAL
✓ price DECIMAL(10, 2)
✗ price FLOAT -- Может быть 19.99999999 вместо 20.00
Проверка таблицы
-- Показать структуру таблицы
DESC users; -- MySQL
\d users; -- PostgreSQL
-- Показать все индексы
SHOW INDEXES FROM users; -- MySQL
SELECT * FROM pg_indexes WHERE tablename = 'users'; -- PostgreSQL
-- Удалить таблицу
DROP TABLE users;
-- Удалить таблицу если существует
DROP TABLE IF EXISTS users;
Вывод: создание таблицы — это не просто CREATE TABLE. Нужно подумать о типах данных, constraints, индексах и масштабируемости. Правильно спроектированная схема экономит месяцы отладки потом.