Тип данных в SQL говорит базе, что лежит в столбце: целое число, деньги с копейками, строка, дата или «да/нет». От типа зависят место на диске, допустимые значения и то, как база сравнивает и сортирует строки. Основных групп пять: числовые, строковые, дата и время, логический и специальные (JSON, двоичные данные).
Короткое правило на старте: идентификаторы храните в INT или BIGINT, деньги в DECIMAL, текст в VARCHAR или TEXT, даты в DATE и TIMESTAMP. Ниже разберём каждую группу на примерах для MySQL, PostgreSQL, SQL Server и SQLite, с запросами и их выводом. Если сам язык пока в новинку, начните с обзора что такое SQL и зачем его учить.
Что такое тип данных в SQL и где его указывают

Тип задают один раз, когда создают таблицу командой CREATE TABLE. Это команда из группы DDL, про группы команд у нас есть отдельный разбор DDL, DML, DCL и TCL, а саму базу перед этим создают по инструкции «Как создать базу данных в SQL».
Вот таблица заказов в MySQL, в которой встречаются почти все популярные типы:
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
customer VARCHAR(100) NOT NULL,
amount DECIMAL(10,2) NOT NULL,
is_paid BOOLEAN DEFAULT FALSE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO orders (customer, amount, is_paid) VALUES ('Анна', 1499.90, TRUE);
SHOW COLUMNS FROM orders;
+------------+---------------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+-------------------+-------------------+
| id | int | NO | PRI | NULL | auto_increment |
| customer | varchar(100) | NO | | NULL | |
| amount | decimal(10,2) | NO | | NULL | |
| is_paid | tinyint(1) | YES | | 0 | |
| created_at | datetime | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+------------+---------------+------+-----+-------------------+-------------------+
Обратите внимание на строку is_paid. Мы написали BOOLEAN, а MySQL сохранил tinyint(1). Одно и то же название типа в разных СУБД может означать разное, поэтому дальше смотрим на каждую базу отдельно.
Шпаргалка: основные типы данных в MySQL, PostgreSQL, SQL Server и SQLite
Стандарт SQL описывает общие типы, но каждая СУБД добавляет свои имена и ограничения. Таблица собрана по официальной документации: MySQL 8.4, PostgreSQL 17, SQL Server и SQLite.
| Что храним | MySQL | PostgreSQL | SQL Server | SQLite |
|---|---|---|---|---|
| Целое число | INT |
integer (int4) |
int |
INTEGER |
| Большое целое | BIGINT |
bigint |
bigint |
INTEGER |
| Точная дробь, деньги | DECIMAL(p,s) |
numeric(p,s) |
decimal(p,s) |
точного типа нет |
| Приближённая дробь | FLOAT, DOUBLE |
real, double precision |
real, float |
REAL |
| Строка с лимитом длины | VARCHAR(n) |
varchar(n) |
varchar(n), nvarchar(n) |
TEXT, лимит не проверяется |
| Длинный текст | TEXT, LONGTEXT |
text |
nvarchar(max) |
TEXT |
| Дата | DATE |
date |
date |
строка или число по договорённости |
| Дата и время | DATETIME, TIMESTAMP |
timestamp, timestamptz |
datetime2 |
строка или число по договорённости |
| Да или нет | BOOLEAN = TINYINT(1) |
boolean |
bit |
INTEGER 0 и 1 |
| Двоичные данные | BLOB, VARBINARY |
bytea |
varbinary |
BLOB |
Если вы работаете с PostgreSQL через графический клиент, типы удобно выбирать прямо в мастере создания таблицы, как в инструкции «Как создать таблицу в pgAdmin 4».
Канал основателя Checkroi Вани Буявца3 800 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединитьсяЧисловые типы данных: INT, DECIMAL и FLOAT
Числовые типы делятся на три семейства: целые, точные дробные и приближённые дробные. Перепутать их дороже всего: ошибка вылезает не сразу, а через полгода, когда в отчёте не сойдутся копейки.
Целые числа: TINYINT, SMALLINT, INT, BIGINT
Целые типы отличаются только размером и диапазоном. Цифры ниже взяты из справки MySQL по целым типам, у PostgreSQL диапазоны smallint, integer и bigint такие же (документация PostgreSQL о числах), а TINYINT там нет.
| Тип | Байт | Диапазон со знаком | Для чего |
|---|---|---|---|
TINYINT |
1 | от −128 до 127 | флаги, оценки от 1 до 5 (в PostgreSQL такого типа нет) |
SMALLINT |
2 | от −32 768 до 32 767 | год, номер этажа, небольшие счётчики |
INT |
4 | от −2 147 483 648 до 2 147 483 647 | id в таблицах до пары миллиардов строк |
BIGINT |
8 | от −9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 | id событий, логов, платежей |
Размер легко проверить в PostgreSQL функцией pg_column_size:
SELECT pg_column_size(1::smallint) AS smallint_b,
pg_column_size(1::int) AS int_b,
pg_column_size(1::bigint) AS bigint_b;
smallint_b | int_b | bigint_b
------------+-------+----------
2 | 4 | 8
Выйти за диапазон не получится: PostgreSQL на SELECT 2147483647::int + 1; отвечает ERROR: integer out of range, MySQL на вставку 2 147 483 648 в столбец INT выдаёт ERROR 1264: Out of range value.
DECIMAL и NUMERIC: точные числа для денег
DECIMAL(p,s) хранит число ровно в том виде, в каком вы его записали. Первое число p задаёт, сколько цифр всего, второе s говорит, сколько из них после запятой. В DECIMAL(10,2) помещается 10 цифр, две из них копейки, значит максимум 99 999 999,99. NUMERIC во всех трёх крупных СУБД работает так же, как DECIMAL.
Лишние знаки после запятой база округлит. Вставим 99,999 в столбец amount из таблицы выше и прочитаем результат запросом SELECT:
INSERT INTO orders (customer, amount) VALUES ('Борис', 99.999);
SELECT customer, amount FROM orders WHERE customer = 'Борис';
customer | amount
----------+--------
Борис | 100.00
Так ведут себя и MySQL, и PostgreSQL. MySQL при этом оставляет заметку Note 1265: Data truncated for column 'amount', которую видно только командой SHOW WARNINGS. Целую часть база не обрезает: на 123 456 789,00 PostgreSQL отвечает numeric field overflow и поясняет, что значение должно быть меньше 10^8.
Пределы точности разные: в MySQL у DECIMAL до 65 цифр (раздел о DECIMAL в документации MySQL), в SQL Server до 38 (decimal и numeric в Transact-SQL), в PostgreSQL до 131 072 цифр до запятой.
FLOAT, REAL и DOUBLE: быстрые, но приближённые
Типы с плавающей точкой хранят число в двоичном виде, и часть десятичных дробей в него не укладывается. Сравните два сложения в MySQL: первое во FLOAT-арифметике, второе в DECIMAL.
SELECT 0.1e0 + 0.2e0 AS float_sum, 0.1 + 0.2 AS decimal_sum;
+---------------------+-------------+
| float_sum | decimal_sum |
+---------------------+-------------+
| 0.30000000000000004 | 0.3 |
+---------------------+-------------+
PostgreSQL на 0.1::float8 + 0.2::float8 показывает те же 0.30000000000000004. Для координат, физических замеров и коэффициентов моделей это не страшно. Для денег, остатков на складе и всего, что потом складывают в отчёте, берите DECIMAL.
Такие расчёты удобно тренировать на задачах с проверкой ответа, их дают многие курсы по SQL из нашего каталога.
Строковые типы данных: CHAR, VARCHAR и TEXT
Строковых типов три основных, и разница между ними в том, как база обращается с длиной.
CHAR(n): строка фиксированной длины. Короткое значение база дополняет пробелами доn.VARCHAR(n): строка переменной длины, но не длиннееnсимволов. В MySQLnбывает от 0 до 65 535 (страница о CHAR и VARCHAR в документации MySQL).TEXT: длинный текст без явного лимита, например описания товаров, комментарии, статьи.
Хвостовые пробелы CHAR при чтении отбрасывает, а VARCHAR хранит как есть. Проверка в PostgreSQL:
SELECT 'ab '::char(5) || '|' AS c, 'ab '::varchar(5) || '|' AS v;
c | v
-----+------
ab| | ab |
В PostgreSQL CHAR не даёт выигрыша в скорости. Документация прямо пишет, что по быстродействию char, varchar и text «практически не отличаются», а character(n) обычно оказывается медленнее остальных (символьные типы PostgreSQL). В большинстве случаев документация советует брать text или varchar(n), а лимит ставить, когда он нужен по смыслу.
Что будет, если строка длиннее лимита
Здесь базы ведут себя по-разному, и это частый источник потерянных данных.
-- PostgreSQL
INSERT INTO orders (customer, amount) VALUES (repeat('я', 101), 10);
ERROR: value too long for type character varying(100)
-- MySQL в строгом режиме (по умолчанию)
ERROR 1406 (22001): Data too long for column 'customer' at row 1
-- MySQL с отключённым строгим режимом: SET SESSION sql_mode = '';
Warning 1265: Data truncated for column 'customer' at row 1
SELECT CHAR_LENGTH(customer) ... -- 100
Без строгого режима MySQL обрезает строку до лимита без ошибки и сохраняет её. Если на старом сервере в sql_mode пусто, проверьте самые длинные значения в таблице: хвосты адресов и названий могли пропасть давно.
Кириллица, байты и NVARCHAR
В VARCHAR(100) число в скобках означает символы, а не байты. Но место на диске считается в байтах, и русская буква в UTF-8 занимает два:
SELECT char_length('Привет') AS chars, octet_length('Привет') AS bytes;
chars | bytes
-------+-------
6 | 12
В MySQL то же самое показывают CHAR_LENGTH и LENGTH. В SQL Server для текста на любых языках традиционно берут NVARCHAR(n), где n от 1 до 4000 или max (nchar и nvarchar в Transact-SQL). Если вы работаете именно с этой СУБД, загляните в курсы по Microsoft SQL Server. Пустая строка и отсутствие значения тоже разные вещи, подробно об этом в статье «NULL в SQL».
Типы для даты и времени

Дату можно сохранить и строкой, но тогда база не проверит 30 февраля и не посчитает разницу между двумя днями. Для дат есть свои типы:
DATEхранит только дату: день рождения, дату договора.TIMEхранит только время суток, например начало смены.DATETIMEиTIMESTAMPхранят дату вместе со временем: момент заказа, входа, платежа.
Несуществующую дату обе базы отклоняют: на '2026-02-30 10:00:00' MySQL отвечает ERROR 1292: Incorrect datetime value, а PostgreSQL date/time field value out of range.
Главная разница в диапазонах. У TIMESTAMP в MySQL верхняя граница 2038-01-19 03:14:07 UTC (документация MySQL о датах), и следующую секунду он уже не примет:
SET time_zone = '+00:00';
INSERT INTO t_ts VALUES ('2038-01-19 03:14:07'); -- ок
INSERT INTO t_ts VALUES ('2038-01-19 03:14:08');
ERROR 1292 (22007): Incorrect datetime value: '2038-01-19 03:14:08' for column 'ts'
Для сроков кредитов, гарантий и подписок, которые уходят за 2038 год, в MySQL берите DATETIME. В PostgreSQL timestamp покрывает годы от 4713 до н. э. до 294276 н. э. (типы даты и времени PostgreSQL), а в SQL Server datetime2 работает с датами от 0001-01-01 до 9999-12-31 (datetime2 в Transact-SQL).
Логический тип и другие специальные типы
BOOLEAN: где он настоящий, а где нет
В PostgreSQL есть отдельный тип boolean со значениями true, false и NULL. Он понимает и строковые варианты (логический тип PostgreSQL):
SELECT 'yes'::boolean AS a, 'off'::boolean AS b, '1'::boolean AS c;
a | b | c
---+---+---
t | f | t
В MySQL BOOLEAN служит синонимом TINYINT(1): ноль считается ложью, любое другое число истиной (описание числовых типов MySQL). Отсюда ловушка: в столбец можно записать 5, и такое значение не равно TRUE.
CREATE TABLE t_b (b BOOLEAN);
INSERT INTO t_b VALUES (5);
SELECT b, b = TRUE AS eq_true, b IS TRUE AS is_true FROM t_b;
+------+---------+---------+
| b | eq_true | is_true |
+------+---------+---------+
| 5 | 0 | 1 |
+------+---------+---------+
В SQL Server логические значения хранят в bit, где TRUE превращается в 1, а FALSE в 0 (тип bit в Transact-SQL). У SQLite отдельного логического типа нет, там те же 0 и 1. Ветвить запрос по такому флагу удобно через оператор CASE.
JSON и двоичные данные
Для данных без жёсткой структуры в MySQL есть тип JSON, в PostgreSQL есть json и jsonb. Второй хранит документ в разобранном двоичном виде: записывать его чуть дольше, а обрабатывать заметно быстрее (типы JSON в PostgreSQL):
SELECT '{"city": "Казань", "tags": ["sql", "json"]}'::jsonb ->> 'city' AS city;
city
--------
Казань
Картинки, PDF и другие файлы в базе хранят в двоичных типах: BLOB в MySQL и SQLite, bytea в PostgreSQL, varbinary в SQL Server. На практике чаще кладут файл в хранилище, а в базе хранят только путь к нему в VARCHAR.
Как преобразовать тип данных: CAST и неявные приведения
Явно поменять тип значения можно функцией CAST, она есть во всех четырёх СУБД:
SELECT CAST('2026-11-04' AS DATE) AS d, CAST('42' AS SIGNED) + 1 AS n; -- MySQL
SELECT CAST('2026-11-04' AS DATE) AS d, '42'::int + 1 AS n; -- PostgreSQL
-- результат в обеих базах
d | n
------------+----
2026-11-04 | 43
Неявные приведения базы делают по-разному. MySQL на SELECT '5' + 3; спокойно отвечает 8. PostgreSQL тоже вернёт 8, пока '5' остаётся литералом, но на значение типа text откажется считать:
SELECT '5'::text + 3;
ERROR: operator does not exist: text + integer
SELECT '5'::text::int + 3 AS n; -- 8
Подменить пустое значение на число по умолчанию помогает функция COALESCE, но типы её аргументов тоже должны совпадать.
Динамическая типизация в SQLite
SQLite устроен иначе. Документация так и пишет: тип там связан с самим значением, а не со столбцом (типы данных в SQLite). Поэтому обычная таблица принимает почти что угодно:
CREATE TABLE t (n INTEGER, s VARCHAR(3));
INSERT INTO t VALUES ('сорок два', 'слишком длинная строка');
SELECT n, typeof(n), s, length(s) FROM t;
сорок два|text|слишком длинная строка|22
Начиная с версии 3.37.0 у SQLite есть таблицы STRICT, где тип проверяется (STRICT-таблицы SQLite). В них разрешены только базовые имена типов, и VARCHAR(3) уже не пройдёт, а строка в столбец INTEGER вызовет cannot store TEXT value in INTEGER column.
Как выбрать тип данных под столбец

Начинайте с вопроса, что вы будете делать со значением: считать, сортировать, искать или просто показывать. Номер телефона выглядит как число, но складывать телефоны никто не будет.
| Столбец | Тип | Почему |
|---|---|---|
| id пользователя или заказа | BIGINT |
запас по росту, переделывать INT на живой таблице больно |
| цена, сумма, баланс | DECIMAL(12,2) |
копейки не теряются при сложении |
| количество на складе | INT |
целое, сравнивается и суммируется |
| email, имя, город | VARCHAR(255) или text |
длина переменная, лимит защищает от мусора |
| телефон, ИНН, индекс | VARCHAR |
нужны ведущие нули и знак «+», считать не нужно |
| описание, отзыв | TEXT |
длина непредсказуема |
| дата рождения | DATE |
время суток не нужно |
| момент события | TIMESTAMP или DATETIME |
сортировка и интервалы по времени |
| оплачен ли заказ | BOOLEAN или bit |
два состояния плюс «неизвестно» |
| настройки, ответ внешнего API | JSON или jsonb |
структура меняется от записи к записи |
Частые ошибки с типами данных
- Деньги во
FLOAT. Симптом: итог в отчёте расходится с суммой строк на копейку. Причина: двоичная дробь, как в примере с 0,1 + 0,2. Решение:DECIMAL(12,2)и пересчёт старых значений черезCAST. - Числа в строковом столбце. Симптом: сортировка ставит 10 перед 2. Причина: строки сравниваются посимвольно, и
ORDER BYпо('9'), ('10'), ('2')выдаёт 10, 2, 9, а по тем же числам 2, 9, 10. Решение: числовой тип илиCASTв сортировке. Как работаетORDER BY, мы разбирали в статье о сортировке по двум столбцам. - Коды и телефоны в
INT. Симптом: код 007 превратился в 7. Причина: у числа нет ведущих нулей,SELECT '007'::intвозвращает 7. Решение:VARCHAR. INTдля id быстрой таблицы. Симптом: вставка падает с ошибкой выхода за диапазон после 2 147 483 647 строк. Решение:BIGINTс первого дня для логов и событий.- Проверка флага через
= TRUEв MySQL. Симптом: часть строк не попадает в выборку. Причина: вTINYINT(1)лежит не только 1. Решение:IS TRUEили условие<> 0.
Где освоить SQL системно
С типами данных вы разобрались, дальше идут запросы с JOIN, индексы, транзакции и проектирование схемы. Разобраться со всем этим по порядку и с практикой быстрее на курсе. Ниже программы по SQL с ценой, длительностью и форматом, а путь до первой работы расписан в плане «Как стать SQL-разработчиком».
| Курс | Школа | Стоимость со скидкой | В рассрочку | Длительность | Обзор курса от Checkroi |
|---|---|---|---|---|---|
| Нейросети для рабочих задач Перейти на сайт курса | 31 290 ₽ | - | 1 месяц | Обзор курса | |
| SQL для анализа данных Перейти на сайт курса | 50 865 ₽ | 6203 ₽/мес. | 2 месяца | Обзор курса | |
| SQL-разработчик: тариф PRO Перейти на сайт курса | 89 900 ₽ | 7491 ₽/мес. | 2 месяца | Обзор курса | |
| SQL-разработчик: тариф Базовый Перейти на сайт курса | 79 900 ₽ | 3329 ₽/мес. | 3 месяца | Обзор курса | |
| Data-Driven подход в разработке продукта: SQL и Yandex DataLens Перейти на сайт курса | 29 990 ₽ | 2999 ₽/мес. | 1 месяц | Обзор курса |
Больше программ — в полном каталоге курсов по SQL




