AAcademyCloud
SQL і бази даних з нуля
Безкоштовний урок-прев'ю

Реляційна модель і перший SELECT

SQL з'явився у 1974-му. Відтоді змінилося все: мови, платформи, підходи — а SQL лишився. Причина в тому, що він описує що треба отримати, а не як це зробити. Оптимізатор бази сам вирішує «як», і робить це краще за більшість людей.

Реляційна модель за п'ять хвилин

Дані живуть у таблицях. Таблиця — набір рядків однакової структури.

courses
┌────┬────────────────┬───────┬─────────────┐
│ id │ title          │ price │ level       │
├────┼────────────────┼───────┼─────────────┤
│  1 │ HTML і CSS     │   249 │ Початковий  │
│  2 │ C# та .NET     │  2499 │ Junior      │
│  3 │ Сервер MMORPG  │  3999 │ Senior      │
└────┴────────────────┴───────┴─────────────┘
  • Стовпець має тип і назву
  • Рядок — один запис
  • Первинний ключ (id) унікально визначає рядок
  • Зовнішній ключ — посилання на рядок іншої таблиці

Ключова ідея: порядок рядків не визначений. Якщо тобі потрібен порядок — вимагай його явно через ORDER BY. Покладатися на те, що «вони й так виходять правильно», не можна: сьогодні так, а після зміни плану запиту — інакше.

Типи даних

CREATE TABLE courses (
    id          SERIAL PRIMARY KEY,      -- автоінкремент (Postgres)
    slug        VARCHAR(64) NOT NULL UNIQUE,
    title       VARCHAR(200) NOT NULL,
    description TEXT,
    price       INTEGER NOT NULL,        -- копійки
    level       VARCHAR(32) NOT NULL DEFAULT 'Початковий',
    published   BOOLEAN NOT NULL DEFAULT FALSE,
    created_at  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Кілька рішень, які варто приймати свідомо:

Гроші — цілим числом у копійках. FLOAT для грошей дає похибку округлення, яка з часом накопичується в реальні розбіжності. Якщо дуже треба дробові — NUMERIC(10,2), ніколи не FLOAT.

NOT NULL за замовчуванням. NULL — не «порожньо», а «невідомо», і він отруює всі порівняння. Дозволяй NULL лише там, де «невідомо» — осмислений стан.

VARCHAR(n) з розумною межею. Не VARCHAR(255) за звичкою: обмеження — це документація того, що ти очікуєш.

SELECT

SELECT * FROM courses;

SELECT title, price FROM courses;

SELECT title AS назва, price / 100 AS ціна_грн FROM courses;

SELECT * зручний у консолі й шкідливий у коді застосунку: додасться стовпець — зміниться результат, і те, що покладалося на порядок полів, зламається. У продакшен-коді перелічуй стовпці явно.

NULL: головна пастка новачка

SELECT * FROM courses WHERE description = NULL;   -- ✗ поверне 0 рядків ЗАВЖДИ
SELECT * FROM courses WHERE description IS NULL;  -- ✓ правильно

NULL не дорівнює нічому, включно з самим собою. NULL = NULL дає не TRUE і не FALSE, а NULL.

SELECT COALESCE(description, 'Без опису') FROM courses;   -- підставити значення
SELECT NULLIF(price, 0);                                  -- зробити NULL, якщо 0

Порядок виконання

Пишемо ми в одному порядку, а виконується інший:

FROM      → звідки беремо
WHERE     → відсіюємо рядки
GROUP BY  → групуємо
HAVING    → відсіюємо групи
SELECT    → обчислюємо стовпці
ORDER BY  → сортуємо
LIMIT     → обмежуємо

Це пояснює річ, об яку спотикаються всі:

SELECT price / 100 AS uah FROM courses WHERE uah > 10;   -- ✗ помилка

WHERE виконується до SELECT, тож псевдоніма uah там ще не існує. Правильно:

SELECT price / 100 AS uah FROM courses WHERE price / 100 > 10;

А от в ORDER BY псевдонім працює — він виконується після SELECT.

Вставка, зміна, видалення

INSERT INTO courses (slug, title, price, level)
VALUES ('sql-databases', 'SQL з нуля', 59900, 'Початковий');

INSERT INTO courses (slug, title, price, level) VALUES
    ('go-basic', 'Go з нуля', 199900, 'Початковий'),
    ('rust-basic', 'Rust', 299900, 'Середній');

UPDATE courses SET price = 49900 WHERE slug = 'sql-databases';

DELETE FROM courses WHERE published = FALSE;

UPDATE і DELETE без WHERE зачіпають усю таблицю. Це найдорожча одруківка в професії. Звичка, яка рятує: спершу напиши той самий запит як SELECT, подивись, що він поверне, і лише потім заміни на UPDATE.

-- 1. Перевірити
SELECT * FROM courses WHERE published = FALSE;
-- 2. І тільки потім
DELETE FROM courses WHERE published = FALSE;

Практика

  1. Постав PostgreSQL (або MySQL) локально чи через Docker.
  2. Створи таблицю courses за прикладом.
  3. Додай 10 рядків, з них два з NULL в описі.
  4. Спробуй знайти рядки з порожнім описом через = NULL і через IS NULL — порівняй результат.
  5. Напиши SELECT, що виводить назву й ціну в гривнях із псевдонімами.

Підсумок

  • Порядок рядків не гарантований без ORDER BY
  • Гроші — цілі копійки, не FLOAT
  • NOT NULL за замовчуванням; NULL = «невідомо», не «порожньо»
  • Порівняння з NULL — тільки IS NULL
  • WHERE виконується до SELECT, тому псевдоніми там недоступні
  • SELECT * — для консолі, не для коду
  • Перед DELETE/UPDATE виконай той самий WHERE як SELECT

Далі — фільтрація й сортування.

Сподобався урок?

Придбайте повний курс, щоб отримати доступ до всіх уроків.

Перейти до курсу