Знакомство с типами данных в SQL

В отличии от языка JavaScript, в языке SQL есть строгая типизация. В каждой таблице у каждой колонки есть свой собственный жестко фиксированный тип данных.

Типов данных очень много, но в отличие от языка Java, тут их так много не потому, что есть типы данных на все случаи жизни. Базы Данных очень зависят от размера данных, поэтому многие типы данных отличаются друг от друга только длиной.

Всего типы данных можно разбить на 5 групп:

  • Числовые типы
  • Строковые типы
  • Типы для хранения даты и времени
  • Объекты: обычно представленные как набор байт
  • Транспортные: JSON и XML

Обычно различные СУБД еще имеют свои собственные типы данных. У каждой СУБД есть своя специализация, поэтому добавление новых типов данных – очень распространенная вещь.

Другое дело, просто добавить новый тип данных недостаточно, нужно добавить и функции, которые будут с ним работать, а также сделать эту работу удобной и быстрой.

Если ты будешь работать на какой-нибудь промышленной (enterprise) СУБД, то скорее всего тебе придется разбираться с ее типами данных и ее функциями. Для чего нужно будет прочитать 2-5 хороших книжек.

Мы же в рамках знакомства с SQL рассмотрим три основные группы типов данных:

  • Числа
  • Строки
  • Даты

Числовые типы в SQL

В языке SQL числовые типы делятся на три группы:

  • Целые типы
  • Числа с фиксированной запятой (фиксированное число знаков после запятой)
  • Числа с плавающей запятой

Начнем с целых чисел. Их всего 5, и они могут быть описаны одной таблицей:

# Имя типа Длина в байтах Аналог из Java Минимальное значение Максимальное значение
1 TINYINT 1 byte -128 127
2 SMALLINT 2 short -32,768 32,767
3 MEDIUMINT 3 -8,388,608 8,388,607
4 INT 4 int -2,147,483,648 2,147,483,647
5 BIGINT 8 long -263 263-1

Типы данных очень похожи на типы данных в Java, однако тут имеется еще один тип integer длиной три байта. Так сделано для возможности экономить на размере.

Далее идут типы с плавающей запятой, как и в Java, их всего два:

# Имя типа Длина в байтах Аналог из Java Минимальное значение Максимальное значение
1 FLOAT 4 float -3.40E+38 +1.18E+38
2 DOUBLE 8 doble -1.79E+308 +1.79E+308

Опять-таки ничего нового. Все, как и в языке Java. Однако, в отличие от Java, в SQL есть еще один специальный тип – вещественной число с фиксированной запятой. Называется оно DECIMAL.

Обычно этот тип используется для хранения сумм денег. Когда пишется название этого типа, то после него обычно указывается, сколько у числа десятичных знаков до запятой и после запятой. Общий формат выглядит так:


DECIMAL(всего_знаков, после_запятой) 

И небольшой пример:


salary DECIMAL(5,2) 

Так мы описали то, что колонка salary может содержать целые числа (максимум 3 знака до запятой) и дробную часть – 2 знака после запятой.

Максимальное количество знаков, которое поддерживает тип DECIMAL – 65.

Строковые типы в SQL

Строки в базе данных могут храниться в двух видах:

  • Строки с фиксированной длиной
  • Строки с переменной длиной

Строки с фиксированной длиной задаются типом CHAR:


CHAR(длина) 

Фиксированная длина значит, что все значения данной колонки будут содержать строго фиксированное количество символов.

Пример строки с фиксированной длиной:


country_code CHAR(2) 

Строки с переменной длиной задаются типом VARCHAR:


VARCHAR(макс_длина) 

Переменная длина значит, что все значения данной колонки будут содержать текст любой длины, но не больше, чем максимальная длина.

Пример строки с переменной длиной:


phone VARCHAR(12) 

У строк с фиксированной длиной есть очень большое преимущество. Если клиент попросил SQL-сервер вернуть ему 1,000,000-ю строку из таблицы, а в таблице строки фиксированной длины, то, зная длину строки, можно легко вычислить байты, которые относятся к искомой строке.

В случае же с переменной длиной строк, так быстро найти нужную строку таблицы не получится. Вспомни скорость доступа к ArrayList и LinkedList, тут примерно похожая ситуация.

Давай сравним, как будут храниться строки разной длины в таблице, в зависимости от типа данных.

Строка CHAR(4) Байт для хранения VARCHAR(4) Байт для хранения
'' ' ' 4 '' 1
'ab' 'ab ' 4 'ab' 3
'abcd' 'abcd' 4 'abcd' 5
'abcdefgh' 'abcd' 4 'abcd' 5

Примечание. Тип VARCHAR требует на один байт больше при той же длине, так как он вынужден дополнительно хранить длину строки.

Временные типы в SQL

В SQL также есть специальные типы для хранения даты и времени. Всего таких типов пять:

# Имя типа Аналог из Java DateTime API Пример Минимальное значение Максимальное значение
1 DATE LocalDate ‘2022-06-30’ ‘1000-01-01’ ‘9999-12-31’
2 TIME LocalTime 'hh:mm:ss[.fraction]' '-838:59:59.000000' '838:59:59.000000'
3 DATETIME LocalDateTime ‘1000-01-01 00:00:00.000000’ '9999-12-31 23:59:59.999999'
4 TIMESTAMP Date '1970-01-01 00:00:01.000000' '2038-01-19 03:14:07.999999'
5 YEAR 1901 2155

Все данные в запросах записываются в виде строки – в одинарных кавычках. Формат записи идет от большего к меньшему:

  • Год
  • Месяц
  • День
  • Час
  • Минута
  • Секунда
  • Доли секунды

Типы DATE, TIME и DATETIME можно условно считать аналогами типов из Java DateTme API: LocalDate, LocalTime, LocalDateTime. Логика примерно та же.

Тип TIMESTAMP хранит данные в виде миллисекунд, прошедших от начала 1970 года (стандарт операционной системы UNIX). Именно в таком виде их хранит и тип Date в языке Java.

Ну и наконец есть тип YEAR, длина которого 1 байт, и который хранит значения от 1 до 255. Поэтому доступный ему диапазон годов – это 1901-2155. Год 1900 данный тип хранить не может, так как значение 0 используется для кодирования значения NULL.

Хранение объектов в SQL

Для хранения объектов или текстов большой длины есть специальные типы. Особо их разбирать не будем, но я все же их перечислю:

# Имя типа Пояснение
1 TEXT Используется для хранения текстов большой длины. При сравнении и сортировки по этому полю используется только первые 100 символов.
2 BLOB Название расшифровывается как Byte Large Object. Хранится в виде просто набора байт. Можно использовать, чтобы, например, хранить в базе данных картинки.
3 CLOB Название расшифровывается как Char Large Object. Используется для хранения текстов большой длины.
4 ENUM Позволяет задать фиксированный набор значений и хранить в качестве значения одно из них.
5 SET Позволяет задать фиксированный набор значений и хранить в качестве значения любое их подмножество. Обычно хранит их как бинарную маску.

Теоретически ты можешь любой Java-объект сериализовать в виде набора байт и сохранить его в базе данных в тип BLOB. Сохранить объект – не проблема. Как с ним работать дальше?

Допустим, таблица хранит миллион объектов в сериализованном виде – как ты будешь выполнять по ним поиск? СУБД только тогда поддерживает определенный тип данных, когда предоставляет обширный набор функций для работы с ним.