← Назад к вопросам

Как создать таблицу в SQL?

1.0 Junior🔥 231 комментариев
#Базы данных и SQL

Комментарии (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

  1. Всегда используй PRIMARY KEY
CREATE TABLE users (id INT PRIMARY KEY, ...)
✗ CREATE TABLE users (username VARCHAR(50), ...)  -- Ошибка!
  1. Используй BIGINT для ID в больших системах
✓ id BIGINT
✗ id INT  -- Переполнится при > 2.1 миллиарда строк
  1. Всегда ставь NOT NULL если есть смысл
✓ email VARCHAR(100) NOT NULL
✗ email VARCHAR(100)  -- NULL это не ошибка
  1. UNIQUE для уникальных полей
✓ username VARCHAR(50) UNIQUE NOT NULL
✗ username VARCHAR(50)  -- Могут быть дубликаты
  1. Timestamps для audit trail
✓ created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
✓ updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP-- Без них нельзя отследить когда менялись данные
  1. FOREIGN KEY для целостности
✓ department_id INT REFERENCES departments(id) ON DELETE CASCADE
✗ department_id INT  -- Может быть несуществующий ID
  1. Индексы для поиска
CREATE INDEX idx_email ON users(email);
✗ -- Без индекса FULL TABLE SCAN при каждом поиске
  1. Для денег используй 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, индексах и масштабируемости. Правильно спроектированная схема экономит месяцы отладки потом.

Как создать таблицу в SQL? | PrepBro