QA Interview Hub · База знань · Тести

SQL

Основи баз даних

таблиці, ключі, типи, NULL

Що таке реляційна база даних і що таке SQL?

Реляційна база даних зберігає дані в таблицях: кожен рядок — це один запис (користувач, рахунок, транзакція), кожен стовпець — його властивість. Таблиці пов'язані між собою ключами: транзакція знає, до якого рахунку належить, рахунок — до якого користувача.

SQL (Structured Query Language) — мова, якою з цими даними працюють: читають, додають, змінюють, видаляють і описують структуру. Головна особливість — SQL декларативний: ти описуєш, що хочеш отримати, а як саме це знайти, вирішує сама СУБД.

Популярні СУБД: PostgreSQL, MySQL, Microsoft SQL Server, Oracle. Базовий SQL у них однаковий, відрізняються деталі: LIMIT проти TOP, функції дат, деякі типи. Приклади в цьому гайді — для PostgreSQL.

На співбесіді: Реляційна база зберігає дані в пов'язаних між собою таблицях, а SQL — це декларативна мова для роботи з ними: я описую, які дані хочу отримати, а база сама вирішує, як їх знайти. Я працював переважно з PostgreSQL, але базовий синтаксис у різних СУБД однаковий.

Що таке первинний і зовнішній ключ?

  • Первинний ключ (PRIMARY KEY) — стовпець, що однозначно ідентифікує рядок. Він унікальний і не може бути NULL. Зазвичай це id.
  • Зовнішній ключ (FOREIGN KEY) — стовпець, що посилається на первинний ключ іншої таблиці. Він створює зв'язок і не дає записати посилання на неіснуючий запис.

У нашій схемі accounts.user_id посилається на users.id. Спроба створити рахунок для користувача 999, якого немає, впаде з помилкою порушення зовнішнього ключа.

CREATE TABLE accounts (
  id       SERIAL PRIMARY KEY,
  user_id  INTEGER NOT NULL REFERENCES users(id),
  currency CHAR(3) NOT NULL,
  balance  NUMERIC(14,2) NOT NULL DEFAULT 0
);
На співбесіді: Первинний ключ однозначно ідентифікує рядок — він унікальний і не буває порожнім. Зовнішній ключ посилається на первинний ключ іншої таблиці і гарантує цілісність: наприклад, не можна створити рахунок для користувача, якого не існує. Для мене як QA це ще й підказка, що тестувати: чи система коректно обробляє такі помилки.

Які типи даних QA варто знати?

ТипДля чогоНа що звернути увагу
INTEGER, BIGINTЦілі числа, IDМежі діапазону: INTEGER до ~2,1 млрд
NUMERIC(p,s) / DECIMALТочні дробові, грошіNUMERIC(14,2) — до 14 цифр, 2 після коми
REAL, DOUBLE PRECISIONНаближені дробовіМають похибку — не для грошей
VARCHAR(n), TEXTРядкиДовжина: що буде з рядком довшим за n
BOOLEANТак / ніМоже бути ще й NULL
DATE, TIMESTAMP, TIMESTAMPTZДати й часІз часовим поясом чи без
UUID, JSONBУнікальні ID, гнучкі даніФормат, вкладені поля

Тип стовпця прямо підказує граничні значення для тестів: максимальна довжина рядка, кількість знаків після коми, діапазон чисел.

На співбесіді: Найчастіше я маю справу з цілими числами для ID, NUMERIC для грошей, рядками, булевими значеннями і датами з часовим поясом чи без. Тип стовпця для мене — джерело граничних значень: максимальна довжина рядка, кількість знаків після коми, діапазон числа. Якщо UI дозволяє більше, ніж база, — це потенційний баг.

Що таке NULL і чим він відрізняється від 0 і порожнього рядка?

NULL означає «значення невідоме або відсутнє». Це не нуль і не порожній рядок:

  • 0 — відоме значення: баланс дорівнює нулю.
  • '' — відоме значення: рядок, у якому нічого немає.
  • NULL — значення невідоме: баланс ще не порахований, телефон не вказаний.

Головна властивість: будь-яке порівняння з NULL дає не TRUE і не FALSE, а UNKNOWN. Навіть NULL = NULL — не TRUE. А арифметика з NULL дає NULL: 100 + NULL = NULL.

Через це NULL — джерело багатьох багів: рядки «зникають» з фільтрів, суми стають порожніми, лічильники не сходяться.

На співбесіді: NULL означає, що значення невідоме або відсутнє, — це не нуль і не порожній рядок. Будь-яке порівняння з NULL дає не «так» і не «ні», а «невідомо», тому рядки з NULL часто випадають з фільтрів, а арифметика з NULL дає NULL. Тому я завжди окремо перевіряю, як система поводиться з порожніми значеннями.

На які групи поділяються команди SQL?

ГрупаКомандиЩо роблять
DQL — запитиSELECTЧитають дані
DML — маніпуляціяINSERT, UPDATE, DELETEЗмінюють дані
DDL — визначенняCREATE, ALTER, DROP, TRUNCATEЗмінюють структуру
DCL — доступGRANT, REVOKEКерують правами
TCL — транзакціїBEGIN, COMMIT, ROLLBACKКерують транзакціями

Іноді SELECT відносять до DML — обидва варіанти зустрічаються.

На співбесіді: Команди SQL поділяють на групи: SELECT для читання, INSERT, UPDATE і DELETE для зміни даних, CREATE, ALTER і DROP для структури, GRANT і REVOKE для прав, а BEGIN, COMMIT і ROLLBACK для транзакцій. Як QA я найчастіше пишу SELECT, рідше — INSERT і UPDATE для підготовки тестових даних, і завжди в транзакції.

Навіщо QA знати SQL?

  • Перевірка результату: UI показує «Переказ успішний», а в базі — правильна сума, статус, комісія, запис в історії?
  • Тестові дані: знайти користувача в потрібному стані або створити його, не проходячи десять кроків в UI.
  • Діагностика: баг у фронтенді, в API чи в самих даних? Запит до бази часто відповідає за хвилину.
  • Цілісність: знайти дублікати, «осиротілі» записи, неможливі стани.
  • Автотести: підготовка й очищення даних, перевірки після дій.
На співбесіді: SQL для мене — це спосіб перевірити правду поза інтерфейсом. UI може показати «успішно», а в базі буде не та сума чи статус. Ще я використовую SQL, щоб швидко знайти або створити тестові дані, локалізувати баг — фронтенд, бекенд чи дані — і шукати порушення цілісності, як-от дублікати чи записи без батьківського.