1. Знайомство з типами даних у SQL

На відміну від мови JavaScript, у мові SQL є строга типізація. У кожній таблиці кожна колонка має свій власний жорстко фіксований тип даних.

Типів даних дуже багато, але на відміну від мови Java, тут їх так багато не тому, що є типи даних на всі випадки життя. Бази даних дуже залежать від розміру даних, тому багато типів даних відрізняються один від одного лише довжиною.

Загалом типи даних можна розбити на 5 груп:

  • Числові типи
  • Строкові типи
  • Типи для зберігання дати та часу
  • Об'єкти: зазвичай представлені як набір байт
  • Транспортні: JSON та XML

Зазвичай різні СУБД мають власні типи даних. Кожна СУБД має свою спеціалізацію, тому додавання нових типів даних — дуже поширена річ.

Інша справа — просто додати новий тип даних недостатньо: потрібно додати й функції, які будуть з ним працювати, а також зробити цю роботу зручною та швидкою.

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

Ми в рамках знайомства з SQL розглянемо три основні групи типів даних:

  • Числа
  • Рядки
  • Дати

2. Кількісні типи в 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 double -1.79E+308 +1.79E+308

Знову ж таки, нічого нового. Все як і в Java. Однак, на відміну від Java, у SQL є ще один спеціальний тип — дійсне число з фіксованою комою. Називається воно DECIMAL.

Зазвичай цей тип використовується для зберігання сум грошей. Коли пишеться назва цього типу, після нього як правило вказується, скільки в кількості десяткових знаків до коми і після коми. Загальний формат має такий вигляд:


DECIMAL(всього_знаків, після_коми) 

І невеликий приклад:


salary DECIMAL(5,2) 

Так ми описали те, що колонка salary може містити цілі числа (максимум 3 знаки до коми) і дробову частину — 2 знаки після коми.

Максимальна кількість символів, яка підтримує тип DECIMAL — 65.

3. Рядкові типи в 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 вимагає на один байт більше за тієї ж довжини, оскільки він змушений додатково зберігати довжину рядка.

4. Тимчасові типи в 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.

5. Зберігання об'єктів у SQL

Для зберігання об'єктів або текстів великої довжини є спеціальні типи. Особливо їх розбирати не будемо, але я все ж таки їх перерахую:

# Ім'я типу Пояснення
1 TEXT Використовується для зберігання текстів великої довжини. При порівнянні та сортуванні цього поля використовуються лише перші 100 символів.
2 BLOB Назва розшифровується як Byte Large Object. Зберігається у вигляді набору байт. Можна використовувати, щоб, наприклад, зберігати в базі даних зображення.
3 CLOB Назва розшифровується як Char Large Object. Використовується для збереження великої довжини текстів.
4 ENUM Дозволяє встановити фіксований набір значень і зберігати як значення одне з них.
5 SET Дозволяє встановити фіксований набір значень і зберігати як значення будь-яку їхню підмножину. Зазвичай зберігає їх як бінарну маску.

Теоретично ти можеш серіалізувати будь-який Java-об'єкт у вигляді набору байт та зберегти його в базі даних у типі BLOB. Зберегти об'єкт — не проблема. Як із ним працювати далі?

Припустимо, таблиця зберігає мільйон об'єктів у серіалізованому вигляді. Як ти виконуватимеш пошук за ними? СУБД лише тоді підтримує певний тип даних, коли надає великий набір функцій для роботи з ним.