Пошук уроків, статей та іншого контенту
Оберіть числові, текстові, логічні, часові та спеціалізовані типи для зберігання значень у таблицях.
Тип даних визначає:
які значення можна зберігати в стовпці;
скільки місця вони можуть займати;
які операції доступні для цих значень;
як PostgreSQL перевіряє правильність даних.
Тип потрібно вказати під час створення таблиці:
CREATE TABLE users (
id integer,
name text,
is_active boolean
);У цьому прикладі:
id зберігає цілі числа;
name — текст;
is_active — логічне значення true або false.
Правильно вибраний тип допомагає базі даних зберігати коректні значення та виконувати запити передбачувано.
Для цілих чисел PostgreSQL має кілька типів:
smallint — від -32768 до 32767;
integer або int — від -2147483648 до 2147483647;
bigint — дуже великі цілі числа.
Найчастіше для звичайних ідентифікаторів, кількості товарів або віку використовують integer.
CREATE TABLE products (
id integer,
quantity integer,
views bigint
);Якщо значення може бути лише невеликим, можна використати smallint. Якщо лічильник може перевищити межі integer, краще одразу обрати bigint.
Тип numeric або decimal призначений для точних чисел. Він особливо важливий для грошей, цін і фінансових розрахунків.
CREATE TABLE invoices (
amount numeric(10, 2)
);numeric(10, 2) означає:
загалом не більше 10 цифр;
2 цифри після десяткового роздільника;
наприклад, 12345678.90 є допустимим значенням.
Для грошових значень не варто використовувати real або double precision, оскільки вони можуть зберігати значення з наближенням.
Типи real і double precision використовують для приблизних числових обчислень:
CREATE TABLE measurements (
temperature real,
distance double precision
);Вони підходять для наукових, інженерних або статистичних даних, де невелика похибка допустима.
texttext зберігає текст довільної довжини:
CREATE TABLE articles (
title text,
content text
);Це типовий вибір для назв, описів, повідомлень і вмісту документів.
varcharvarchar(n) зберігає текст довжиною не більше n символів:
CREATE TABLE profiles (
username varchar(50)
);Якщо текст довший за 50 символів, PostgreSQL повідомить про помилку під час вставлення.
Тип varchar без обмеження довжини фактично поводиться подібно до text:
CREATE TABLE comments (
body varchar
);У PostgreSQL між text і varchar без обмеження довжини зазвичай немає помітної різниці в продуктивності. Обмеження довжини варто використовувати лише тоді, коли воно є частиною правила предметної області.
char(n)char(n) — текст фіксованої довжини. PostgreSQL доповнює короткі значення пробілами.
Для більшості прикладних даних цей тип не потрібен. Зазвичай краще використовувати text або varchar.
Тип boolean зберігає логічне значення:
true;
false;
NULL, якщо значення не задане.
CREATE TABLE tasks (
title text,
is_completed boolean
);Під час вставлення можна використовувати TRUE і FALSE:
INSERT INTO tasks (title, is_completed)
VALUES
('Вивчити типи даних', TRUE),
('Створити таблицю', FALSE);Для логічних властивостей краще використовувати назви на кшталт is_active, has_access або is_completed. Вони показують, що стовпець має логічний тип.
PostgreSQL має окремі типи для різних часових значень.
datedate зберігає лише календарну дату:
CREATE TABLE events (
event_date date
);Приклад значення:
INSERT INTO events (event_date)
VALUES ('2026-09-01');Цей тип підходить для дня народження, дати платежу або дати події, якщо час доби не потрібен.
timetime зберігає час без дати:
CREATE TABLE opening_hours (
opens_at time,
closes_at time
);Наприклад: 09:00:00 або 18:30:00.
timestamptimestamp зберігає дату й час без інформації про часовий пояс:
CREATE TABLE appointments (
starts_at timestamp
);Цей тип може бути доречним для значень, які не залежать від часового поясу, наприклад часу роботи місцевого закладу.
timestamptztimestamptz — це скорочена назва типу timestamp with time zone. Він призначений для моментів часу, які можуть відображатися в різних часових поясах.
CREATE TABLE messages (
created_at timestamptz
);Для часу створення запису, часу оновлення або часу надсилання повідомлення зазвичай використовують timestamptz.
Поточний час можна отримати за допомогою now():
INSERT INTO messages (created_at)
VALUES (now());Важливо розрізняти:
дату й час події без часового поясу — timestamp;
конкретний момент часу — timestamptz.
PostgreSQL має типи для даних, які не зручно зберігати як звичайний текст.
uuiduuid зберігає універсальний унікальний ідентифікатор:
CREATE TABLE api_keys (
id uuid,
name text
);UUID часто використовують як ідентифікатор, який створюється не послідовно:
INSERT INTO api_keys (id, name)
VALUES (
'550e8400-e29b-41d4-a716-446655440000',
'Основний ключ'
);Значення UUID має спеціальний формат із шістнадцяткових символів і дефісів.
jsonbjsonb зберігає структуровані дані у форматі JSON. На відміну від звичайного тексту, PostgreSQL розуміє структуру такого значення.
CREATE TABLE settings (
user_id integer,
options jsonb
);
INSERT INTO settings (user_id, options)
VALUES (
1,
'{"theme": "dark", "notifications": true}'
);Значення jsonb може містити об'єкти, масиви, рядки, числа й логічні значення.
Отримати окреме поле JSON можна оператором ->>:
SELECT options->>'theme' AS theme
FROM settings;jsonb зручний для гнучких даних, структура яких може відрізнятися між записами. Дані, які мають стабільну структуру й активно фільтруються, зазвичай краще зберігати в окремих стовпцях.
PostgreSQL підтримує масиви значень одного типу. Для масиву текстових значень використовують text[]:
CREATE TABLE articles (
title text,
tags text[]
);
INSERT INTO articles (title, tags)
VALUES (
'Типи даних PostgreSQL',
ARRAY['postgresql', 'sql', 'database']
);Прочитати масив можна звичайним SELECT:
SELECT title, tags
FROM articles;Масиви підходять для простих списків, наприклад набору тегів. Якщо елементи списку мають власні властивості або з ними потрібно складно працювати, зазвичай створюють окрему таблицю.
enumenum описує обмежений набір допустимих значень:
CREATE TYPE order_status AS ENUM (
'new',
'paid',
'shipped',
'cancelled'
);
CREATE TABLE orders (
id integer,
status order_status
);Тепер стовпець status може містити лише одне зі значень, оголошених у order_status.
Такий тип зручний для невеликого стабільного набору значень. Якщо список статусів часто змінюється або статуси мають додаткові властивості, краще зберігати їх в окремій таблиці.
Іноді значення потрібно явно перетворити в інший тип. Для цього використовують оператор :: або конструкцію CAST.
SELECT '42'::integer;Цей запит перетворює текст '42' на число integer.
Еквівалентний запис через CAST:
SELECT CAST('42' AS integer);Приклад перетворення числа на текст:
SELECT 2026::text;Перетворення можливе лише тоді, коли значення сумісне з цільовим типом. Наприклад, текст 'hello' не можна безпосередньо перетворити на integer.
NULL і тип данихNULL означає, що значення відсутнє або невідоме. Це не те саме, що:
0;
порожній рядок '';
false.
Наприклад:
CREATE TABLE contacts (
name text,
phone text
);
INSERT INTO contacts (name, phone)
VALUES ('Олена', NULL);У цьому рядку номер телефону не вказаний. Перевіряти NULL потрібно за допомогою IS NULL або IS NOT NULL:
SELECT name
FROM contacts
WHERE phone IS NULL;Порівняння через phone = NULL не працює як перевірка відсутнього значення.
Нижче наведено таблицю, яка використовує кілька типів даних:
DROP TABLE IF EXISTS products;
CREATE TABLE products (
id integer,
name text NOT NULL,
price numeric(10, 2) NOT NULL,
quantity integer NOT NULL,
is_available boolean NOT NULL,
created_at timestamptz NOT NULL,
tags text[],
extra jsonb
);
INSERT INTO products (
id,
name,
price,
quantity,
is_available,
created_at,
tags,
extra
)
VALUES (
1,
'Механічна клавіатура',
2499.99,
12,
TRUE,
now(),
ARRAY['keyboard', 'usb'],
'{"color": "black", "layout": "US"}'
);
SELECT
id,
name,
price,
quantity,
is_available,
created_at,
tags,
extra->>'color' AS color
FROM products;У цьому прикладі:
integer використано для ідентифікатора та кількості;
text — для назви;
numeric(10, 2) — для точної ціни;
boolean — для доступності;
timestamptz — для моменту створення;
text[] — для тегів;
jsonb — для додаткових властивостей товару.
Під час проєктування таблиці поставте такі запитання:
Значення є цілим числом, точним десятковим числом чи приблизним числом?
Чи потрібне обмеження довжини тексту?
Чи зберігається лише дата, лише час або конкретний момент часу?
Чи може значення бути відсутнім?
Чи має значення фіксований набір варіантів?
Чи має структура даних бути гнучкою, як у jsonb?
Чи є значення простим списком одного типу, для якого підходить масив?
Тип повинен відповідати змісту даних, а не лише поточному прикладу. Наприклад, ціну слід зберігати як numeric, навіть якщо зараз усі ціни мають лише дві цифри після коми.
CREATE TABLE wrong_prices (
price text
);У такому випадку сортування може бути нечисловим: значення '100' може опинитися перед '20'.
Для цін використовуйте numeric, а для кількості — integer або bigint.
real або double precisionЦі типи призначені для приблизних значень. Для фінансових даних використовуйте numeric(p, s).
timestamp для глобальних моментів часуЯкщо подія відбувається в конкретний момент і користувачі можуть бути в різних часових поясах, використовуйте timestamptz.
NULL через =Неправильно:
SELECT *
FROM contacts
WHERE phone = NULL;Правильно:
SELECT *
FROM contacts
WHERE phone IS NULL;jsonbjsonb не повинен автоматично замінювати звичайні стовпці. Якщо поле має стабільну структуру, наприклад email, price або created_at, краще створити для нього окремий стовпець із відповідним типом.
Для цілих чисел використовуйте smallint, integer або bigint.
Для точних десяткових значень, особливо грошей, використовуйте numeric.
Для приблизних обчислень підходять real і double precision.
Для більшості текстових значень використовуйте text або varchar з обмеженням довжини.
Логічні значення зберігаються в boolean.
Для дат використовуйте date, для часу — time, для дати й часу — timestamp або timestamptz.
uuid призначений для унікальних ідентифікаторів.
jsonb зберігає структуровані гнучкі дані.
Масиви зберігають списки значень одного типу.
enum обмежує значення визначеним набором варіантів.
NULL означає відсутність значення та перевіряється через IS NULL.