Как изменить тип данных в SQL

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

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

Postgres

ALTER TABLE users ALTER COLUMN age TYPE BIGINT;

MySQL

ALTER TABLE users MODIFY COLUMN age BIGINT;

1. С cast (USING)

Если автоматическое преобразование невозможно:

-- Postgres: строка в число
ALTER TABLE users
ALTER COLUMN age TYPE INT USING age::INT;

-- с обработкой невалидных
ALTER TABLE users
ALTER COLUMN age TYPE INT USING NULLIF(age, '')::INT;

2. VARCHAR → TEXT

Обычно совместимо:

ALTER TABLE users ALTER COLUMN description TYPE TEXT;

3. INT → BIGINT

Совместимо:

ALTER TABLE users ALTER COLUMN id TYPE BIGINT;

4. FLOAT → NUMERIC

Может потерять точность. Обычно безопасно:

ALTER TABLE sales
ALTER COLUMN amount TYPE NUMERIC(10, 2) USING amount::NUMERIC(10, 2);

5. TIMESTAMP без зоны → с зоной

-- Postgres
ALTER TABLE events
ALTER COLUMN created_at TYPE TIMESTAMPTZ
USING created_at AT TIME ZONE 'UTC';

6. TEXT → JSON / JSONB

ALTER TABLE events
ALTER COLUMN payload TYPE JSONB USING payload::JSONB;

Если в данных есть невалидный JSON — запрос упадёт. Сначала проверьте.

7. Уменьшение размера (опасно)

-- если в данных есть строки длиннее 50 — ошибка
ALTER TABLE users ALTER COLUMN bio TYPE VARCHAR(50);

Проверьте до:

SELECT MAX(LENGTH(bio)) FROM users;

8. Safe migration (без блокировки prod)

Для больших таблиц ALTER COLUMN TYPE может блокировать. Шаблон:

-- 1. Добавить новую колонку
ALTER TABLE users ADD COLUMN age_new BIGINT;

-- 2. Заполнить батчами (в приложении или через скрипт)
UPDATE users SET age_new = age::BIGINT WHERE age_new IS NULL
LIMIT 10000;

-- 3. Создать триггер для синхронизации новых записей
CREATE TRIGGER sync_age BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE update_age_new();

-- 4. Проверить, что всё заполнено
SELECT COUNT(*) FROM users WHERE age_new IS NULL;

-- 5. Переименовать
ALTER TABLE users DROP COLUMN age;
ALTER TABLE users RENAME COLUMN age_new TO age;

Для мелких таблиц — просто ALTER COLUMN TYPE.

9. DATE ↔ STRING

-- string → date
ALTER TABLE events
ALTER COLUMN created_at TYPE DATE
USING TO_DATE(created_at, 'YYYY-MM-DD');

-- date → string
ALTER TABLE events
ALTER COLUMN date_str TYPE VARCHAR(10)
USING TO_CHAR(date_col, 'YYYY-MM-DD');

10. BOOLEAN ↔ INT

-- int → bool
ALTER TABLE users
ALTER COLUMN is_premium TYPE BOOLEAN
USING (is_premium::INT = 1);

-- bool → int
ALTER TABLE users
ALTER COLUMN flag_col TYPE INT
USING (flag_col::INT);

CAST vs ALTER COLUMN

Задача Инструмент
Постоянно изменить тип в таблице ALTER TABLE ... TYPE
Временно преобразовать в запросе CAST / ::

CAST в запросе:

SELECT age::INT FROM users;
SELECT CAST(age AS INT) FROM users;  -- SQL стандарт

Часто просматривают

  • NUMERIC → INT (потеря дробной части): (amount::INT)
  • INT → NUMERIC (безопасно)
  • VARCHAR → INT (нужен USING)
  • TEXT → DATE (нужен TO_DATE)

Частые ошибки

Нежизнеспособные значения

-- упадёт, если в age есть '30 лет' (не число)
ALTER TABLE users ALTER COLUMN age TYPE INT USING age::INT;

Сначала:

SELECT * FROM users WHERE age !~ '^\d+$';  -- регексп на число
-- почистить или исключить

Потеря точности

FLOAT → INT теряет дробь. NUMERIC(10, 2) с числом 1234567.89 — не помещается (2 знака дроби + 8 целых > 10).

Блокировка prod-таблицы

ALTER COLUMN TYPE на большой таблице блокирует запись. Делайте в техокно или через shadow-колонку.

Несоответствие в коде

Код ожидает INT, а колонка стала STRING — запросы падают. Обновите код синхронно.

Связанные темы

FAQ

Можно ли изменить тип без потери данных?

Если типы совместимы (VARCHAR → TEXT, INT → BIGINT) — да. С преобразованием (VARCHAR → INT) — зависит от данных.

Блокирует ли ALTER COLUMN TYPE?

Postgres: для некоторых преобразований — да (нужна перезапись). Для совместимых — нет.

CAST или ::?

:: — синтаксис Postgres, короче. CAST(... AS ...) — стандарт SQL, работает везде.

Что делать, если ALTER падает на prod?

Shadow-колонка + пакетная миграция + rename. Подробнее в разделе «Safe migration».


Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.