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

Какие знаешь типы данных SQL?

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

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Типы данных SQL: полный справочник

Типы данных — это основа структуры БД. Рассмотрю все основные типы, их особенности и когда их использовать.

Категория 1: Числовые типы

Целые числа (Integer)

TINYINT          → -128 до 127 (1 байт)              [MySQL]
SMALLINT-32768 до 32767 (2 байта)         [PostgreSQL, MySQL]
INTEGER / INT-2^31 до 2^31-1 (4 байта)         [Стандарт]
BIGINT-2^63 до 2^63-1 (8 байт)          [PostgreSQL, MySQL]

Примеры использования:
TINYINT: статус (0=активный, 1=удален)
SMALLINT: количество товара (0-1000)
INT: ID пользователя (обычно используют)
BIGINT: timestamp в миллисекундах, большие ID

Числа с плавающей точкой (Float/Decimal)

FLOAT            → приблизительные (4 байта)
DOUBLE           → приблизительные (8 байт)
DECIMAL(p, s)    → точные (p = всего цифр, s = после запятой)
NUMERIC(p, s)    → синоним DECIMAL

Примеры:
FLOAT(7, 2)      → 99999.99  (7 цифр, 2 после запятой)
DECIMAL(10, 2)   → 99999999.99

Правило: используйте DECIMAL для денег

-- ❌ ПЛОХО - потеря точности
CREATE TABLE orders (
    price FLOAT
);

INSERT INTO orders VALUES (0.1);
INSERT INTO orders VALUES (0.2);
SELECT SUM(price) FROM orders;
-- Результат может быть 0.30000000000004 вместо 0.3

-- ✅ ХОРОШО - точные вычисления
CREATE TABLE orders (
    price DECIMAL(10, 2)
);

INSERT INTO orders VALUES (0.10);
INSERT INTO orders VALUES (0.20);
SELECT SUM(price) FROM orders;
-- Результат: 0.30 (точно)

Категория 2: Строки (String)

Текстовые типы

CHAR(n)          → фиксированная длина n байт
                   "Hello" в CHAR(10) = "Hello     " (с пробелами)
                   Используйте для кодов: "US", "RU"

VARCHAR(n)       → переменная длина до n байт
                   "Hello" в VARCHAR(10) = "Hello" (без лишних пробелов)
                   Используйте для имен, email, адресов

TEXT             → очень длинный текст (до 4GB в MySQL)
CLOBCharacter Large Object (PostgreSQL)
LONGTEXT         → MySQL, до 4GB

Примеры использования:

Когда использовать CHAR vs VARCHAR

-- ✅ CHAR для фиксированной длины
CREATE TABLE countries (
    code CHAR(2)              -- "US", "FR", "RU"
);

-- ✅ VARCHAR для переменной длины
CREATE TABLE users (
    email VARCHAR(255),       -- разная длина
    username VARCHAR(100),
    full_name VARCHAR(255)
);

Сравнение размер

Данные:         "Hello"

CHAR(20)   :    5 + 15 пробелов = 20 байт (всегда)
VARCHAR(20):    1 байт (длина) + 5 байт (данные) = 6 байт

ВЫВОД: VARCHAR экономит место для текста переменной длины

Категория 3: Дата и время

Типы DateTime

DATE'YYYY-MM-DD'                    (3 байта)
TIME'HH:MM:SS'                       (3 байта)
DATETIME / TIMESTAMP'YYYY-MM-DD HH:MM:SS'           (8 байт)
TIMESTAMP'YYYY-MM-DD HH:MM:SS' автоматически обновляется
TIMESTAMPZ             → с указанием временной зоны (PostgreSQL)

Примеры:

Правило: всегда используйте TIMESTAMP с часовым поясом

-- ❌ НЕПРАВИЛЬНО - теряется информация о часовом поясе
CREATE TABLE events (
    event_time DATETIME
);
-- Проблема: 2026-03-28 10:00:00 (какой часовой пояс?)

-- ✅ ПРАВИЛЬНО - сохраняется часовой пояс
CREATE TABLE events (
    event_time TIMESTAMPTZ  -- PostgreSQL
);

-- или

CREATE TABLE events (
    event_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  -- MySQL
    timezone VARCHAR(50)
);

Работа с датами

-- Текущая дата
SELECT CURRENT_DATE;           -- 2026-03-28
SELECT CURRENT_TIME;           -- 15:30:45
SELECT CURRENT_TIMESTAMP;      -- 2026-03-28 15:30:45

-- Операции с датами
SELECT CURRENT_DATE + INTERVAL '1 day';        -- 2026-03-29
SELECT CURRENT_TIMESTAMP - INTERVAL '1 week';  -- неделю назад

-- Разница между датами
SELECT AGE(CURRENT_TIMESTAMP, created_at) AS account_age
FROM users;

Результат: "1 year 3 months 5 days"

Категория 4: Булевы значения (Boolean)

BOOLEAN / BOOL   → TRUE or FALSE (1 байт в PostgreSQL)
                   0 = FALSE, 1 = TRUE (в MySQL)

Примеры использования:

Использование boolean

CREATE TABLE users (
    id UUID PRIMARY KEY,
    email VARCHAR(255),
    is_active BOOLEAN DEFAULT TRUE,      -- активный пользователь
    is_admin BOOLEAN DEFAULT FALSE,      -- администратор
    email_verified BOOLEAN DEFAULT FALSE -- email подтвержден
);

-- Запросы
SELECT * FROM users WHERE is_active = TRUE;
SELECT * FROM users WHERE is_active;  -- эквивалентно
SELECT * FROM users WHERE NOT is_admin;

Категория 5: JSON/JSONB

JSON             → текстовое хранилище JSON (PostgreSQL, MySQL)
JSONB            → бинарное хранилище JSON с индексами (PostgreSQL)

Преимущества:
✅ Гибкая структура данных
✅ Индексирование отдельных полей
✅ Встроенные функции для работы с JSON

Примеры

CREATE TABLE users (
    id UUID PRIMARY KEY,
    name VARCHAR(255),
    metadata JSONB  -- Хранить дополнительные данные
);

INSERT INTO users VALUES (
    'user_123',
    'John',
    '{"phone": "+1234567890", "address": {"city": "NYC"}, "tags": ["vip", "premium"]}'
);

-- Доступ к JSON полям
SELECT 
    name,
    metadata->>'phone' as phone,                 -- строка
    metadata->'address'->>'city' as city,        -- вложенный объект
    metadata->'tags'->0 as first_tag            -- массив
FROM users;

-- Поиск в JSON
SELECT * FROM users WHERE metadata @> '{"tags": ["vip"]}';

-- Создание индекса на JSON
CREATE INDEX idx_users_metadata_tags ON users USING GIN (metadata->'tags');

Категория 6: UUID

UUID             → глобально уникальный идентификатор (16 байт)
                   Пример: 550e8400-e29b-41d4-a716-446655440000

Преимущества:
✅ Глобально уникален (работает в распределенных системах)
✅ Безопасен (невозможно угадать)
✅ Не раскрывает количество записей
✅ Может быть сгенерирован на клиенте

Использование UUID

CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),  -- PostgreSQL
    email VARCHAR(255),
    created_at TIMESTAMP
);

-- в MySQL используйте UUID() функцию
CREATE TABLE users (
    id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
    email VARCHAR(255)
);

Категория 7: ENUM

ENUM             → один из предопределенных значений (PostgreSQL)

Пример:

Использование ENUM

-- Создание ENUM типа
CREATE TYPE order_status AS ENUM ('pending', 'processing', 'shipped', 'delivered', 'cancelled');

-- Использование в таблице
CREATE TABLE orders (
    id UUID PRIMARY KEY,
    status order_status DEFAULT 'pending',
    created_at TIMESTAMP
);

-- Вставка данных
INSERT INTO orders (id, status) VALUES ('order_1', 'processing');

-- Преимущества ENUM:
✅ Ограничивает возможные значения
✅ Экономит место (2 байта вместо VARCHAR)
✅ Быстрее сравнение

-- Недостатки:
❌ Сложно добавить новое значение (нужна миграция)
❌ Не все БД поддерживают

Категория 8: Бинарные данные

BINARY(n)       → фиксированная длина (n байт)
VARBINARY(n)    → переменная длина до n байт
BLOBBinary Large Object (до 4GB)
BYTEA           → в PostgreSQL

Использование:

Когда использовать BLOB/BYTEA

-- ❌ ПЛОХО - хранить файлы в БД
CREATE TABLE documents (
    id UUID PRIMARY KEY,
    file BLOB  -- 10MB файл
);
-- Проблема: медленный backup, замедляет запросы

-- ✅ ХОРОШО - хранить в S3, ссылку в БД
CREATE TABLE documents (
    id UUID PRIMARY KEY,
    s3_url VARCHAR(500),    -- ссылка на S3
    file_size INTEGER,
    mime_type VARCHAR(50)
);

Специальные типы (PostgreSQL)

Array

CREATE TABLE user_tags (
    user_id UUID,
    tags TEXT[]  -- массив текста
);

INSERT INTO user_tags VALUES ('user_1', ARRAY['vip', 'premium', 'beta']);

SELECT * FROM user_tags WHERE 'vip' = ANY(tags);

Range типы

CREATE TABLE availability (
    id UUID PRIMARY KEY,
    available_dates DATERANGE  -- диапазон дат
);

INSERT INTO availability VALUES ('slot_1', '[2026-03-28, 2026-03-31)');

-- Проверка пересечения
SELECT * FROM availability 
WHERE available_dates && DATERANGE('2026-03-29', '2026-04-01');

Сравнение типов для конкретных случаев

Для ID:

INT - может переполниться
✅ BIGINT - безопаснее
✅ UUID - лучший выбор для распределенных систем

Для email:

VARCHAR(1000) - слишком большая
✅ VARCHAR(255) - достаточно (RFC 5321 = 254 символа)

Для IP адреса:

VARCHAR(15) - неправильная валидация
✅ INET (PostgreSQL) - встроенная валидация
✅ VARCHAR(45) - для IPv6

Для телефона:

BIGINT - теряет лидирующие нули
✅ VARCHAR(20) - хранит как строка

Выбор правильного размера

Tип                 | Размер  | Максимум          | Использование
────────────────────┼─────────┼───────────────────┼──────────────
TINYINT             | 1 байт  | 255               | status
SMALLINT            | 2 байта | 65535             | количество
INT                 | 4 байта | 2.1B              | ID
BIGINT              | 8 байт  | 9.2 квинтиллион   | timestamp
DECIMAL(10,2)       | 4-8     | 99999999.99       | деньги
CHAR(2)             | 2 байта | "US"              | коды
VARCHAR(255)        | 1-256   | 255 символов      | строки
DATE                | 3 байта | 2038 год          | дата
TIMESTAMPTZ         | 8 байт  |                   | точный момент
UUID                | 16 байт |                   | ID
JSON                | варьирующ |                 | гибкие данные
BOOLEAN             | 1 байт  | TRUE/FALSE        | флаги

Best Practices

1. Используйте правильные типы

✅ Деньги → DECIMAL(10,2)
✅ Дата/время → TIMESTAMP WITH TIMEZONE
✅ ID → UUID или BIGINT
✅ Флаги → BOOLEAN

2. Выбирайте минимальный размер

❌ VARCHAR(1000) для email (max 255)
✅ VARCHAR(255) для email

❌ INT для дня месяца (0-31)
✅ SMALLINT или TINYINT

3. Используйте CONSTRAINT для ограничения значений

CREATE TABLE products (
    id UUID PRIMARY KEY,
    quantity INT CHECK (quantity >= 0),
    discount DECIMAL(5,2) CHECK (discount BETWEEN 0 AND 100),
    status VARCHAR(20) CHECK (status IN ('active', 'inactive', 'archived'))
);

4. Всегда используйте TIMESTAMP WITH TIMEZONE

❌ created_at TIMESTAMP
✅ created_at TIMESTAMPTZ DEFAULT NOW()

5. Документируйте семантику типов

-- Комментарии помогают разработчикам
CREATE TABLE users (
    id UUID PRIMARY KEY COMMENT "Global unique ID",
    email VARCHAR(255) NOT NULL COMMENT "Email адрес, уникален",
    age INT COMMENT "Возраст в годах, 0-150",
    balance DECIMAL(10,2) COMMENT "Баланс в USD с 2 знаками"
);

Вывод

Основные категории типов SQL:

  1. Числовые: INT, BIGINT, DECIMAL
  2. Строки: VARCHAR, TEXT, CHAR
  3. Дата/время: DATE, TIMESTAMP, TIMESTAMPTZ
  4. Булевы: BOOLEAN
  5. JSON: JSON, JSONB (гибкие данные)
  6. UUID: глобально уникальные ID
  7. ENUM: ограниченный набор значений
  8. Бинарные: BLOB, BYTEA

Золотые правила:

  • Используйте DECIMAL для денег
  • Используйте UUID для ID в распределенных системах
  • Используйте TIMESTAMPTZ для дат
  • Выбирайте минимальный размер для экономии памяти
  • Ограничивайте значения constraints