Prog Academy
RU UA
Питання на співбесіді Data Analyst: 39 питань з відповідями і задачі з SQL
Кар'єра в IT

Питання на співбесіді Data Analyst: 39 питань з відповідями і задачі з SQL

На співбесіді Junior Data Analyst перевіряють чотири речі: чи вмієте ви дістати дані запитом SQL, чи розумієте базову статистику, чи можете зібрати звіт у таблицях або BI-інструменті та чи здатні пояснити цифру людині з бізнесу. У статті — 39 питань з короткими відповідями, згрупованих за сімома темами: SQL, статистика, Excel, Power BI, pandas, продуктові метрики та комунікація. Найбільший блок — SQL, із запитами та їхнім реальним результатом. Після питань — чотири практичні задачі з розв'язками, типові помилки і план підготовки на два тижні.

Я тренер Prog Academy з Power BI і викладач вищої школи, тому бачу підготовку до співбесід з боку студентів. Найчастіше підводить не забута функція, а невміння пояснити, чому цифра вийшла саме такою: звідки взялися рядки, що сталося з порожніми значеннями, чому підсумок не сходиться із сусіднім звітом. Відповіді нижче побудовані так, щоб ви могли вимовити їх уголос, а потім показати на прикладі.

Актуально на жовтень 2026 року

Усі SQL-запити виконано в SQLite 3.51, результати у статті — реальний вивід. Там, де синтаксис або поведінка в PostgreSQL і MySQL відрізняється, це вказано поруч із запитом. Приклади pandas запущено на pandas 2.3. Формули DAX — стандартні міри з документації Microsoft; запустити їх поза Power BI неможливо, тому вони наведені без виводу. Добір питань — авторський, на основі викладацького досвіду, а не статистика зі співбесід.

Як проходить співбесіда на Data Analyst?

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

ЕтапЩо перевіряютьЯк готуватися
Скринінг із рекрутеромМотивацію, досвід і проєкти, очікування щодо формату та оплати, рівень англійськоїРозповідь про себе на дві хвилини, один проєкт у форматі «задача — дані — що зробив — результат», вилка очікувань
Технічне інтерв'юSQL, статистику, інструменти з вакансії, розуміння метрикПитання з цієї статті: проговорити відповіді вголос і написати запити руками
Практичне завданняУміння дійти від сирих даних до висновку: live-coding з SQL або домашнє завдання з набором данихЗадачі з розділу «Практичні задачі»; звичка спершу перевіряти дані, потім рахувати
Фінальна зустрічЯк ви спілкуєтеся, ставите запитання і реагуєте на нечітку постановку задачіПідготувати запитання до команди і приклад ситуації, коли ви уточнювали задачу або захищали висновок

Про зарплату на співбесіді запитують уже на першому етапі. Цифр тут не наводимо, щоб вони не застарівали: медіанні зарплати за рівнями зібрано на сторінці зарплати Data Analyst.

Які теми запитують у Junior і Middle?

Від Junior чекають упевненого SQL, базової статистики та одного інструмента звітності; від Middle — тих самих тем глибше, плюс самостійності в постановці задачі. Таблиця показує, що саме перевіряють у кожній темі. Рівні вказано з досвіду авторки, без частот: набір тем у конкретній компанії визначає вакансія.

ТемаЩо перевіряютьРівень
SQL: SELECT, WHERE, JOIN, GROUP BYНаписати запит до двох-трьох таблиць і пояснити, скільки рядків він повернеJunior
SQL: підзапити, CTE, NULL, дублікатиРозбити задачу на кроки, не загубити і не розмножити рядкиJunior
SQL: віконні функціїРанжування, накопичувальний підсумок, порівняння з попереднім періодомJunior — основи, Middle — впевнено
СтатистикаСереднє і медіана, розкид, кореляція, зміст p-valueJunior
A/B-тестиДизайн експерименту, розмір вибірки, інтерпретація результатуJunior — принцип, Middle — дизайн
Excel / Google SheetsФункції пошуку, зведені таблиці, очищення данихJunior
Power BI та візуалізаціяМодель даних, зв'язки, міри, вибір діаграмиJunior
DAX: CALCULATE і контекстиПояснити, чому міра повертає саме це числоJunior — основи, Middle — впевнено
Python і pandasЧитання, фільтрація, групування, об'єднання, пропускиJunior, якщо вказано у вакансії
Метрики продуктуКонверсія, утримання, когорти, LTV, розслідування падіння метрикиJunior — визначення, Middle — розслідування
КомунікаціяПояснити висновок без термінів, уточнити нечітку задачуJunior і Middle

Питання з SQL

SQL — головний блок технічного інтерв'ю аналітика: перевіряють JOIN, агрегацію, NULL і віконні функції. Усі приклади нижче працюють із двома таблицями: клієнти і замовлення. Створіть їх у себе і запускайте запити під час читання — у SQL розуміння приходить через руки. Якщо ви починаєте з нуля, спершу прочитайте SQL для початківців.

CREATE TABLE customers (
  id          INTEGER PRIMARY KEY,
  name        TEXT NOT NULL,
  city        TEXT,
  signup_date TEXT NOT NULL
);

CREATE TABLE orders (
  id          INTEGER PRIMARY KEY,
  customer_id INTEGER REFERENCES customers(id),
  order_date  TEXT NOT NULL,
  amount      INTEGER,
  status      TEXT NOT NULL
);

INSERT INTO customers VALUES
  (1, 'Olena',  'Kyiv',  '2026-01-10'),
  (2, 'Taras',  'Lviv',  '2026-01-25'),
  (3, 'Iryna',  'Kyiv',  '2026-02-03'),
  (4, 'Maksym', NULL,    '2026-02-14'),
  (5, 'Sofiia', 'Odesa', '2026-03-01');

INSERT INTO orders VALUES
  (1, 1, '2026-01-12', 1200, 'paid'),
  (2, 1, '2026-02-05',  800, 'paid'),
  (3, 2, '2026-01-28',  450, 'paid'),
  (4, 2, '2026-02-05',  450, 'refunded'),
  (5, 3, '2026-02-10', 2000, 'paid'),
  (6, 3, '2026-03-02', 1200, 'paid'),
  (7, 4, '2026-03-15', NULL, 'pending'),
  (8, 1, '2026-03-20',  800, 'paid'),
  (9, 3, '2026-03-28',  300, 'paid');

У даних навмисно є незручні місця: клієнт без міста, клієнт без замовлень, замовлення без суми і два замовлення в один день. Саме на таких рядках будуються питання інтерв'ю. У SQLite дати зберігаються як текст у форматі ISO; у PostgreSQL і MySQL для цих стовпців використовуйте тип DATE.

У якому порядку виконується запит SELECT?

Логічний порядок такий: FROM і JOIN, потім WHERE, GROUP BY, HAVING, віконні функції, SELECT, DISTINCT, ORDER BY і наприкінці LIMIT. Пишемо ми запит в одному порядку, а виконується він в іншому.

Із цього порядку випливають три практичні правила. У WHERE не можна використовувати агрегатну функцію — групи ще не зібрані. У WHERE не можна використовувати віконну функцію — її результат фільтрують у зовнішньому запиті або CTE. А псевдонім стовпця із SELECT надійно доступний лише в ORDER BY: у WHERE і HAVING PostgreSQL його не прийме, хоча SQLite і MySQL у HAVING приймають. Тому в переносному запиті вираз повторюють.

Що хочуть почути: не завчений список, а висновок із нього — чому умову на суму групи пишуть у HAVING.

Чим WHERE відрізняється від HAVING?

WHERE відбирає рядки до групування, HAVING — групи після нього. Тому умову на окремий рядок пишуть у WHERE, а умову на результат агрегатної функції — у HAVING.

SELECT customer_id,
       COUNT(*)    AS orders_cnt,
       SUM(amount) AS revenue
FROM orders
WHERE status = 'paid'
GROUP BY customer_id
HAVING SUM(amount) > 1000
ORDER BY revenue DESC;
customer_id  orders_cnt  revenue
-----------  ----------  -------
3            3           3500
1            3           2800

Спершу WHERE прибрав повернення і неоплачене замовлення, потім рядки згрупувалися за клієнтом, і лише після цього HAVING відкинув клієнта 2 з виручкою 450. У HAVING повторено вираз SUM(amount), а не псевдонім revenue: так запит працює і в PostgreSQL.

Які бувають JOIN і чим INNER JOIN відрізняється від LEFT JOIN?

INNER JOIN повертає лише ті рядки, для яких знайшлася пара в обох таблицях. LEFT JOIN повертає всі рядки лівої таблиці, а там, де пари праворуч немає, підставляє NULL. Ще є RIGHT JOIN (дзеркало лівого), FULL OUTER JOIN (усі рядки обох таблиць) і CROSS JOIN (кожен із кожним).

SELECT c.name, COUNT(o.id) AS orders_cnt
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
GROUP BY c.id, c.name
ORDER BY c.id;
name    orders_cnt
------  ----------
Olena   3
Taras   2
Iryna   3
Maksym  1
Sofiia  0

З INNER JOIN Sofiia з результату зникла б: у неї немає замовлень. Зверніть увагу на COUNT(o.id): COUNT(*) повернув би для неї 1, бо рядок із порожньою правою частиною все одно існує. FULL OUTER JOIN є в PostgreSQL і в SQLite починаючи з версії 3.39, у MySQL його немає.

Чому LEFT JOIN іноді поводиться як INNER JOIN?

Тому що умова на праву таблицю стоїть у WHERE. У рядків без пари стовпці правої таблиці дорівнюють NULL, порівняння NULL = 'paid' не дає істини, і WHERE такі рядки відкидає. Щоб зберегти всі рядки ліворуч, умову переносять в ON.

SELECT c.name, COUNT(o.id) AS paid_orders
FROM customers AS c
LEFT JOIN orders AS o
       ON o.customer_id = c.id AND o.status = 'paid'
GROUP BY c.id, c.name
ORDER BY c.id;
name    paid_orders
------  -----------
Olena   3
Taras   1
Iryna   3
Maksym  0
Sofiia  0

Той самий запит із WHERE o.status = 'paid' замість умови в ON повертає три рядки: Maksym і Sofiia зникають. Типова помилка: звіт «клієнти та їхні оплачені замовлення» мовчки губить клієнтів без оплат, і цього ніхто не помічає.

Як знайти клієнтів, у яких немає жодного замовлення?

Два стандартні способи: LEFT JOIN з перевіркою IS NULL за ключем правої таблиці або NOT EXISTS. Обидва повертають те саме.

SELECT c.name
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
WHERE o.id IS NULL;

SELECT c.name
FROM customers AS c
WHERE NOT EXISTS (
  SELECT 1 FROM orders AS o WHERE o.customer_id = c.id
);
name
------
Sofiia

Третій варіант — NOT IN (SELECT customer_id FROM orders) — небезпечний: якщо в підзапиті трапиться хоча б один NULL, запит не поверне жодного рядка. Що хочуть почути: що ви знаєте про цю пастку і тому обираєте NOT EXISTS.

Чим відрізняються COUNT(*), COUNT(стовпець) і COUNT(DISTINCT стовпець)?

COUNT(*) рахує рядки, COUNT(стовпець) — рядки, де стовпець не NULL, COUNT(DISTINCT стовпець) — кількість різних значень, теж без NULL. Решта агрегатних функцій — SUM, AVG, MIN, MAX — порожні значення пропускають.

SELECT COUNT(*)               AS all_rows,
       COUNT(amount)          AS with_amount,
       COUNT(DISTINCT amount) AS distinct_amounts,
       SUM(amount)            AS total,
       AVG(amount)            AS avg_amount
FROM orders;
all_rows  with_amount  distinct_amounts  total  avg_amount
--------  -----------  ----------------  -----  ----------
9         8            5                 7200   900.0

Середнє дорівнює 7200 / 8, а не 7200 / 9: замовлення без суми в розрахунок не потрапило. Якщо порожню суму треба рахувати нулем, пишуть AVG(COALESCE(amount, 0)) — і це вже інше число, 800. Який варіант правильний, вирішує зміст даних, а не SQL.

Як NULL поводиться в порівняннях і фільтрах?

NULL означає «значення невідоме», тому будь-яке порівняння з ним дає не істину і не хибу, а NULL. Перевіряють його лише через IS NULL та IS NOT NULL, а замінюють функцією COALESCE.

SELECT NULL = NULL        AS eq_null,
       NULL IS NULL       AS is_null,
       COALESCE(NULL, 0)  AS coalesced,
       1 NOT IN (2, NULL) AS not_in_with_null;
eq_null  is_null  coalesced  not_in_with_null
-------  -------  ---------  ----------------
         1        0

Порожня клітинка у виводі — це NULL. Практичний наслідок: запит WHERE city <> 'Kyiv' на нашій таблиці повертає двох клієнтів, а не трьох — Maksym із невідомим містом не потрапляє ні в «Київ», ні в «не Київ». Щоб він потрапив, додають OR city IS NULL. Під час сортування за зростанням SQLite і MySQL ставлять NULL першими, PostgreSQL — останніми.

Чим підзапит відрізняється від CTE?

Підзапит — це запит усередині іншого запиту; CTE (загальний табличний вираз, WITH) — той самий підзапит, винесений нагору і названий. Результат однаковий, різниця в читабельності: CTE можна читати згори вниз за кроками і використовувати в запиті кілька разів.

WITH customer_revenue AS (
  SELECT customer_id, SUM(amount) AS revenue
  FROM orders
  WHERE status = 'paid'
  GROUP BY customer_id
)
SELECT c.name, r.revenue
FROM customer_revenue AS r
JOIN customers AS c ON c.id = r.customer_id
WHERE r.revenue > (SELECT AVG(revenue) FROM customer_revenue)
ORDER BY r.revenue DESC;
name   revenue
-----  -------
Iryna  3500
Olena  2800

Тут customer_revenue використано двічі: як джерело рядків і для розрахунку середньої виручки на клієнта (2250). З вкладеними підзапитами цей розрахунок довелося б написати два рази. CTE підтримують SQLite, PostgreSQL і MySQL починаючи з версії 8.0.

Що таке віконна функція і чим вона відрізняється від GROUP BY?

Віконна функція рахує значення за групою рядків, але не згортає їх: у результаті лишається кожен вихідний рядок, і поруч із ним з'являється обчислене значення. GROUP BY лишає один рядок на групу.

SELECT id, customer_id, amount,
       SUM(amount) OVER (PARTITION BY customer_id) AS customer_total
FROM orders
WHERE status = 'paid'
ORDER BY customer_id, id;
id  customer_id  amount  customer_total
--  -----------  ------  --------------
1   1            1200    2800
2   1            800     2800
8   1            800     2800
3   2            450     450
5   3            2000    3500
6   3            1200    3500
9   3            300     3500

Звідси один крок до частки замовлення у виручці клієнта: 100.0 * amount / SUM(amount) OVER (PARTITION BY customer_id). PARTITION BY задає, на які групи ділити рядки, ORDER BY усередині OVER — порядок усередині групи. Подробиці — в документації SQLite і PostgreSQL; у MySQL віконні функції є з версії 8.0.

Чим відрізняються ROW_NUMBER, RANK і DENSE_RANK?

Усі три нумерують рядки в заданому порядку, а різняться поведінкою за однакових значень. ROW_NUMBER завжди дає унікальні номери, RANK ставить рівним рядкам однаковий номер і потім пропускає номери, DENSE_RANK ставить однаковий номер без пропусків.

SELECT id, amount,
       ROW_NUMBER() OVER (ORDER BY amount DESC) AS row_num,
       RANK()       OVER (ORDER BY amount DESC) AS rnk,
       DENSE_RANK() OVER (ORDER BY amount DESC) AS dense_rnk
FROM orders
WHERE status = 'paid'
ORDER BY amount DESC, id;
id  amount  row_num  rnk  dense_rnk
--  ------  -------  ---  ---------
5   2000    1        1    1
1   1200    2        2    2
6   1200    3        2    2
2   800     4        4    3
8   800     5        4    3
3   450     6        6    4
9   300     7        7    5

Що хочуть почути: коли що обирати. «Один рядок на клієнта» — ROW_NUMBER. «Три найбільші суми разом зі збігами» — DENSE_RANK. І застереження: за рівних значень ROW_NUMBER розподіляє номери між ними довільно, тому в ORDER BY вікна додають другий стовпець, наприклад id.

Як порахувати накопичувальний підсумок?

Функцією SUM з вікном, у якому задано порядок: SUM(amount) OVER (ORDER BY order_date). Важлива деталь — рамка вікна: за замовчуванням вона охоплює всі рядки з тим самим значенням сортування, що й поточний.

SELECT id, order_date, amount,
       SUM(amount) OVER (ORDER BY order_date) AS total_default,
       SUM(amount) OVER (
         ORDER BY order_date, id
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS total_rows
FROM orders
WHERE amount IS NOT NULL
ORDER BY order_date, id;
id  order_date  amount  total_default  total_rows
--  ----------  ------  -------------  ----------
1   2026-01-12  1200    1200           1200
3   2026-01-28  450     1650           1650
2   2026-02-05  800     2900           2450
4   2026-02-05  450     2900           2900
5   2026-02-10  2000    4900           4900
6   2026-03-02  1200    6100           6100
8   2026-03-20  800     6900           6900
9   2026-03-28  300     7200           7200

Два замовлення від 5 лютого у стовпці total_default отримали однаковий підсумок 2900: рамка за замовчуванням — RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, і «поточний рядок» у ній означає всі рядки з тією самою датою. Явна рамка ROWS з однозначним сортуванням дає порядковий підсумок. Поведінка однакова в SQLite, PostgreSQL і MySQL.

Як порівняти значення з попереднім періодом?

Функцією LAG: вона повертає значення з попереднього рядка вікна. Спершу дані агрегують до потрібного періоду, потім до кожного рядка підтягують попередній.

WITH monthly AS (
  SELECT strftime('%Y-%m', order_date) AS month,
         SUM(amount)                   AS revenue
  FROM orders
  WHERE status = 'paid'
  GROUP BY strftime('%Y-%m', order_date)
)
SELECT month, revenue,
       LAG(revenue) OVER (ORDER BY month)           AS prev_revenue,
       revenue - LAG(revenue) OVER (ORDER BY month) AS diff
FROM monthly
ORDER BY month;
month    revenue  prev_revenue  diff
-------  -------  ------------  ----
2026-01  1650
2026-02  2800     1650          1150
2026-03  2300     2800          -500

У першого місяця попереднього значення немає, тому LAG повернув NULL, і різниця теж NULL. Парна функція LEAD дивиться на наступний рядок. Місяць із дати в кожній СУБД отримують по-своєму: strftime('%Y-%m', order_date) у SQLite, to_char(order_date, 'YYYY-MM') у PostgreSQL, DATE_FORMAT(order_date, '%Y-%m') у MySQL.

Як знайти і видалити дублікати?

Знайти — групуванням за стовпцями, які мають бути унікальними, з умовою HAVING COUNT(*) > 1. Залишити по одному рядку — через ROW_NUMBER з PARTITION BY за тими самими стовпцями. Приклад на таблиці заявок, де одна адреса пошти трапляється кілька разів:

CREATE TABLE leads (
  id         INTEGER PRIMARY KEY,
  email      TEXT NOT NULL,
  created_at TEXT NOT NULL
);

INSERT INTO leads VALUES
  (1, '[email protected]',  '2026-03-01'),
  (2, '[email protected]',  '2026-03-02'),
  (3, '[email protected]',  '2026-03-05'),
  (4, '[email protected]', '2026-03-06'),
  (5, '[email protected]',  '2026-03-09'),
  (6, '[email protected]',  '2026-03-10');

SELECT email, COUNT(*) AS cnt
FROM leads
GROUP BY email
HAVING COUNT(*) > 1
ORDER BY cnt DESC;
email             cnt
----------------  ---
[email protected]  3
[email protected]  2

Перша заявка кожної людини:

SELECT id, email, created_at
FROM (
  SELECT id, email, created_at,
         ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at) AS rn
  FROM leads
) AS t
WHERE rn = 1
ORDER BY id;
id  email              created_at
--  -----------------  ----------
1   [email protected]   2026-03-01
2   [email protected]   2026-03-02
4   [email protected]  2026-03-06

Фізично видалити зайві рядки можна запитом DELETE FROM leads WHERE id NOT IN (SELECT MIN(id) FROM leads GROUP BY email) — у SQLite він лишає ті самі три рядки, так само він працює в PostgreSQL. MySQL такий запит відхилить: там не можна в підзапиті читати таблицю, з якої видаляєте, і підзапит загортають у похідну таблицю. Що хочуть почути: що спершу ви з'ясуєте, який рядок вважається «правильним» і звідки дублікати взялися, і лише потім видалятимете.

Питання зі статистики

Зі статистики в Junior перевіряють не формули, а розуміння: яку міру обрати, що означає розкид і як не зробити висновок, якого дані не підтримують. Визначення і приклади можна звірити з довідником NIST/SEMATECH e-Handbook of Statistical Methods.

Чим середнє відрізняється від медіани і коли що використовувати?

Середнє — сума значень, поділена на їхню кількість; медіана — значення посередині впорядкованого ряду. Середнє чутливе до викидів, медіана — ні, тому для скошених даних (доходи, чеки, час на сайті) чесніше показувати медіану.

import statistics as st

salaries = [900, 1000, 1100, 1200, 1300, 9000]

print(st.mean(salaries))
print(st.median(salaries))
print(round(st.pstdev(salaries), 1))  # population standard deviation
print(round(st.stdev(salaries), 1))   # sample standard deviation (n - 1)
2416.6666666666665
1150.0
2947.0
3228.3

Одне значення 9000 підняло середнє до 2417, хоча п'ятеро із шести отримують не більше ніж 1300. Медіана 1150 описує «типову» людину краще. Що хочуть почути: що ви спершу подивитеся на розподіл і лише потім оберете міру, а у звіті покажете обидві, якщо вони сильно розходяться.

Що таке дисперсія і стандартне відхилення?

Дисперсія — середній квадрат відхилення значень від середнього, стандартне відхилення — корінь із дисперсії. Обидві показують розкид, але стандартне відхилення виражене в тих самих одиницях, що й самі дані, тому його простіше інтерпретувати.

На співбесіді часто уточнюють різницю між генеральною і вибірковою формулою: для вибірки суму квадратів ділять на n − 1, а не на n, щоб оцінка розкиду не була заниженою. У прикладі вище це 3228,3 проти 2947,0. В Excel це функції STDEV.S і STDEV.P, у pandas метод std() за замовчуванням рахує вибірковий варіант. І ще одне спостереження з того самого прикладу: викид роздуває стандартне відхилення так само, як середнє.

Що таке нормальний розподіл і які ще розподіли ви знаєте?

Нормальний розподіл — симетричний, дзвоноподібний, повністю задається середнім і стандартним відхиленням; у межах одного, двох і трьох стандартних відхилень від середнього лежить приблизно 68, 95 і 99,7 % значень. Багато статистичних методів спираються на нього.

Дані аналітика часто нормальними не є. Суми покупок і доходи скошені вправо — довгий хвіст із великих значень. Кількість подій за період (замовлення за годину) описує розподіл Пуассона. Результат «так / ні» (купив чи ні) — біноміальний. Що хочуть почути: що ви перевіряєте форму розподілу гістограмою, перш ніж застосовувати середнє, стандартне відхилення або тест, розрахований на нормальність.

Чим кореляція відрізняється від причинності?

Кореляція показує, що дві величини змінюються узгоджено; причинність — що зміна однієї спричиняє зміну іншої. З першого друге не випливає.

Зв'язок може пояснюватися третім чинником: продажі морозива і кількість звернень із сонячними опіками зростають разом, бо обидва залежать від погоди. Причину і наслідок можна переплутати місцями. Нарешті, за великої кількості метрик якісь збіжаться випадково. Коефіцієнт Пірсона до того ж вимірює лише лінійний зв'язок і чутливий до викидів. Що хочуть почути: що причинність перевіряють експериментом — A/B-тестом, — а за спостережними даними формулюють гіпотезу, а не висновок.

Що таке p-value?

P-value — це ймовірність отримати такий самий або сильніший ефект, як у наших даних, за умови, що насправді різниці немає (нульова гіпотеза правильна). Що воно менше, то гірше дані узгоджуються з припущенням «ефекту немає».

Типова помилка — сказати, що p-value — це ймовірність того, що нульова гіпотеза правильна, або ймовірність, що результат випадковий. Це неправильно: p-value рахується в припущенні, що гіпотеза вже правильна. Ще два уточнення, які цінують інтерв'юери. Поріг значущості (часто 0,05) обирають до експерименту, а не після. І статистична значущість нічого не каже про розмір ефекту: на великій вибірці значущою виявиться і різниця, яка бізнесу байдужа. Ці положення сформульовано в заяві Американської статистичної асоціації про p-value.

Як улаштований A/B-тест?

Користувачів випадково ділять на групи, одній показують поточний варіант, іншій — змінений, і порівнюють заздалегідь обрану метрику. Випадковий розподіл потрібен, щоб групи відрізнялися лише самою зміною.

Порядок дій, який варто назвати:

  1. сформулювати гіпотезу й одну головну метрику;
  2. до запуску визначити мінімальний ефект, який важливий, рівень значущості і потрібний розмір вибірки;
  3. запустити тест на повний цикл — зазвичай кратно тижням, щоб урахувати будні й вихідні;
  4. не зупиняти тест у момент, коли різниця «стала значущою»: підглядання збільшує кількість хибних спрацювань;
  5. перевірити, що групи вийшли очікуваного розміру, і лише потім порівнювати метрику.

Що хочуть почути: що рішення ухвалюють за заздалегідь оголошеними правилами, а не добирають метрику і сегмент під бажаний результат.

Що таке зміщення вибірки і як його помітити?

Зміщення вибірки виникає, коли дані, за якими ми робимо висновок, систематично відрізняються від сукупності, про яку хочемо його зробити. Тоді навіть акуратний розрахунок дає хибну відповідь.

Приклади з практики аналітика: опитування про задоволеність, на яке відповідають лише найбільш задоволені і найбільш незадоволені; аналіз «успішних клієнтів» без тих, хто пішов (помилка вцілілого); висновок про всіх користувачів за даними одного каналу залучення. Щоб помітити зміщення, запитують: як ці рядки потрапили в таблицю і кого в ній немає? Потім порівнюють склад вибірки з відомим складом усієї бази — за каналами, регіонами, давністю реєстрації.

Питання з Excel і таблиць

Про таблиці запитують три речі: функції пошуку, зведені таблиці та очищення даних. Відповіді однаково застосовні до Excel і Google Sheets; назви функцій наведено англійські. Про те, де закінчуються можливості таблиць і починається BI, є окремий розбір — Power BI чи Excel.

Чим VLOOKUP відрізняється від XLOOKUP та INDEX + MATCH?

VLOOKUP шукає значення в першому стовпці діапазону і повертає значення зі стовпця правіше за його номером. XLOOKUP приймає стовпець пошуку і стовпець результату окремо, тому вміє шукати ліворуч і не ламається, коли вставляють стовпці. Зв'язка INDEX + MATCH робить те саме у версіях, де XLOOKUP немає.

Деталі, про які запитують:

  • у VLOOKUP останній аргумент за замовчуванням означає приблизний збіг, тому для точного пошуку пишуть FALSE; у XLOOKUP точний збіг — за замовчуванням;
  • якщо значення не знайдено, VLOOKUP поверне #N/A, а в XLOOKUP є аргумент для значення «якщо не знайдено»;
  • за кількох збігів обидві функції повертають перший — дублікати в довіднику дають тиху помилку.

Описи аргументів — у довідці Microsoft про VLOOKUP і XLOOKUP.

Що таке зведена таблиця і коли вона потрібна?

Зведена таблиця — інструмент, який групує рядки вихідної таблиці за обраними полями і рахує за групами підсумки: суму, кількість, середнє. За змістом це GROUP BY без написання запиту.

Поля розкладають за чотирма областями: рядки, стовпці, значення і фільтри. Зведена потрібна, коли треба швидко подивитися на дані в різних розрізах — виручку за місяцями і містами, кількість замовлень за статусами. Що хочуть почути: вимоги до вихідних даних. Один рядок — один запис, один рядок заголовків, без об'єднаних клітинок і проміжних підсумків усередині діапазону, числа і дати зберігаються як числа і дати, а не як текст. Покроковий опис — у довідці Microsoft про зведені таблиці.

Як ви очищаєте дані в таблиці перед аналізом?

Спершу дивлюся, що саме не так, і лише потім виправляю — на копії, не чіпаючи вихідний аркуш. Порядок перевірки зазвичай такий:

  1. Структура: один рядок заголовків, немає об'єднаних клітинок і порожніх рядків усередині даних.
  2. Типи: числа і дати, збережені як текст, — їх видають вирівнювання за лівим краєм і сума, що дорівнює нулю.
  3. Текст: зайві пробіли (TRIM), різний регістр, варіанти написання одного значення — «Київ», «київ», «Kyiv».
  4. Дублікати: спершу порахувати, потім вирішити, які рядки зайві, і лише тоді видаляти.
  5. Пропуски і викиди: зрозуміти їхню причину, перш ніж заповнювати або відкидати.

Що хочуть почути: що кожну зміну ви можете відтворити і пояснити. Тому повторюване очищення переносять із ручних правок у Power Query, SQL або pandas.

Питання з Power BI та візуалізації

У блоці BI перевіряють, чи розумієте ви модель даних: звідки звіт бере цифру і чому вона змінюється, коли обирають фільтр. Формули нижче — стандартні міри; запустити їх поза Power BI неможливо, тому вони наведені без виводу і звірені з довідником функцій DAX на Microsoft Learn. Покроковий вступ до мови — у статті DAX для початківців.

Що таке схема «зірка» і навіщо вона потрібна?

«Зірка» — це модель, у якій у центрі стоїть таблиця фактів із подіями та числами (продажі, замовлення), а навколо неї — таблиці вимірів з описами (клієнти, товари, календар). Факти пов'язані з вимірами за ключами.

Така модель дає три переваги: фільтри з вимірів передбачувано поширюються на факти, міри пишуться простіше, а модель займає менше пам'яті, бо текстові описи не повторюються в кожному рядку фактів. Протилежність — одна широка таблиця, де все змішано: на ній формули ускладнюються, а підсумки починають двоїтися. Microsoft прямо рекомендує «зірку» для моделей Power BI в настанові щодо схеми «зірка».

Які бувають зв'язки між таблицями в Power BI?

Зв'язок описують дві характеристики: кардинальність і напрям фільтрації. Кардинальність буває «один до багатьох», «один до одного» і «багато до багатьох»; напрям — односторонній або двосторонній.

Робочий стандарт — «один до багатьох» з одностороннім фільтром: вимір (сторона «один») фільтрує таблицю фактів (сторона «багато»). Обрали місто в таблиці клієнтів — відфільтрувалися продажі. Двосторонню фільтрацію і зв'язки «багато до багатьох» вмикають лише свідомо: вони можуть давати неоднозначні шляхи фільтра і неочікувані підсумки. Між двома таблицями активним може бути лише один зв'язок; решта неактивні й вмикаються в мірі функцією USERELATIONSHIP. Докладніше — в документації про зв'язки в моделях.

Чим міра відрізняється від обчислюваного стовпця?

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

Amount = Sales[Quantity] * Sales[Price]

Total Sales = SUM(Sales[Amount])

Перша формула — обчислюваний стовпець у таблиці Sales: вона бачить поточний рядок. Друга — міра: те саме визначення повертає загальну суму в картці, суму за містом у рядку таблиці і суму за місяць на графіку. Практичне правило: стовпець потрібен, коли значення використовується у зрізі, на осі або у зв'язку; усе, що є підсумком, середнім або часткою, — міра. Типова помилка: порахувати частку або середнє у стовпці, а потім підсумувати її у візуалі. Офіційні описи: міри та обчислювані стовпці.

Що робить CALCULATE і що таке контекст фільтра?

Контекст фільтра — це набір фільтрів, що діють на клітинку звіту: зрізи, рядки і стовпці візуалу, фільтри сторінки. CALCULATE обчислює вираз у зміненому контексті фільтра: додає нові фільтри, замінює наявні або знімає їх.

Kyiv Sales =
CALCULATE([Total Sales], Customers[City] = "Kyiv")

Sales Share =
DIVIDE(
    [Total Sales],
    CALCULATE([Total Sales], ALL(Customers[City]))
)

Перша міра завжди показує продажі Києва: фільтр за містом у CALCULATE замінює той, що прийшов із візуалу. Друга рахує частку міста: у знаменнику ALL знімає фільтр за містом, тому там загальний підсумок. DIVIDE використовують замість оператора ділення, щоб ділення на нуль повертало порожнє значення, а не помилку.

Що хочуть почути: різницю між контекстом фільтра і контекстом рядка. Контекст рядка є в обчислюваних стовпцях і функціях-ітераторах на кшталт SUMX; CALCULATE перетворює його на контекст фільтра — це називають переходом контексту. Синтаксис і приклади — в описі CALCULATE.

Як ви обираєте тип діаграми?

Від питання, на яке має відповісти графік, а не від того, що гарніше. Спершу формулюю питання однією фразою, потім добираю форму.

ПитанняДіаграма
Як показник змінювався в часі?Лінійний графік
Яка категорія більша?Стовпчикова або лінійчата діаграма, відсортована за значенням
З чого складається ціле?Стовпчикова з накопиченням; кругова — лише для двох-трьох часток
Як розподілені значення?Гістограма
Чи пов'язані дві величини?Точкова діаграма
Одне число і його порівняння з ціллюКартка з показником

До цього варто додати: вісь стовпчикової діаграми починається з нуля, колір несе зміст, а не прикрашає, і на одному екрані дашборда лишається тільки те, що допомагає ухвалити рішення. Перелік візуалів Power BI — в документації Microsoft.

DA

Ті самі теми — з викладачем і домашніми завданнями

Програма курсу Data Analytics у Prog Academy складається з чотирьох модулів: Power BI, Python для дата аналітики, AI Start і SQL. Повна програма розрахована на 5 місяців; у ній є модель даних і функції DAX, SQL від SELECT до підзапитів, NumPy і Pandas, очищення даних та основи статистики.

Програма курсу Data Analytics →

Питання з Python і pandas

Якщо Python указаний у вакансії, запитують п'ять операцій pandas: прочитати файл, відфільтрувати, згрупувати, об'єднати таблиці та обробити пропуски. Приклади працюють із файлом orders.csv — тими самими замовленнями, що й у блоці SQL, але в «брудному» вигляді: один рядок продубльовано, в одного немає міста і суми. Ширший огляд — у статті Python для аналізу даних.

order_id,customer,city,order_date,amount,status
1,Olena,Kyiv,2026-01-12,1200,paid
2,Olena,Kyiv,2026-02-05,800,paid
3,Taras,Lviv,2026-01-28,450,paid
4,Taras,Lviv,2026-02-05,450,refunded
5,Iryna,Kyiv,2026-02-10,2000,paid
6,Iryna,Kyiv,2026-03-02,1200,paid
7,Maksym,,2026-03-15,,pending
8,Olena,Kyiv,2026-03-20,800,paid
8,Olena,Kyiv,2026-03-20,800,paid
9,Iryna,Kyiv,2026-03-28,300,paid

З чого ви починаєте роботу з новим набором даних у pandas?

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

import pandas as pd

df = pd.read_csv("orders.csv", parse_dates=["order_date"])

print(df.shape)
print(df.dtypes)
print(df.isna().sum())
(10, 6)
order_id               int64
customer              object
city                  object
order_date    datetime64[ns]
amount               float64
status                object
dtype: object
order_id      0
customer      0
city          1
order_date    0
amount        1
status        0
dtype: int64

Уже видно два факти. Стовпець amount став дробовим, хоча у файлі цілі числа: у ньому є пропуск, а звичайний цілочисельний тип NaN зберігати не вміє. І дата прочиталася як дата лише тому, що вказано parse_dates, — без нього це був би рядок тексту.

Як відфільтрувати рядки за кількома умовами?

Логічною маскою у квадратних дужках: кожну умову беруть у круглі дужки і з'єднують операторами & (і), | (або), ~ (не).

big_kyiv = df[(df["city"] == "Kyiv") & (df["amount"] >= 1000)]
print(big_kyiv[["order_id", "customer", "amount"]])
   order_id customer  amount
0         1    Olena  1200.0
4         5    Iryna  2000.0
5         6    Iryna  1200.0

Типова помилка: написати and замість & або забути дужки. Слова and і or працюють з одним логічним значенням, а не зі стовпцем, і pandas видасть помилку про неоднозначність. Дужки потрібні, бо в & пріоритет вищий, ніж у порівняння. Щоб обрати рядки і стовпці одночасно, використовують df.loc[маска, стовпці]; правила індексації описано в документації pandas.

Як згрупувати дані й порахувати кілька показників?

Методом groupby з agg: в agg для кожного нового стовпця вказують вихідний стовпець і функцію. Це прямий аналог GROUP BY у SQL.

df = df.drop_duplicates()

report = (
    df[df["status"] == "paid"]
    .groupby("customer", as_index=False)
    .agg(orders=("order_id", "count"), revenue=("amount", "sum"))
    .sort_values("revenue", ascending=False)
)
print(report)
  customer  orders  revenue
0    Iryna       3   3500.0
1    Olena       3   2800.0
2    Taras       1    450.0

Цифри збігаються із SQL-запитом із блоку вище — так і має бути, якщо дані очищено однаково. Без drop_duplicates() в Olena вийшло б чотири замовлення і 3600. Одну відмінність від SQL варто назвати: за замовчуванням groupby відкидає рядки, де ключ групування порожній, а GROUP BY збирає NULL в окрему групу. У pandas цю поведінку змінює параметр dropna=False (настанова з groupby).

Як об'єднати дві таблиці і чим merge схожий на JOIN?

Методом merge: параметр on задає ключ, а how — тип об'єднання: inner, left, right, outer. Це ті самі JOIN, тільки за замовчуванням merge робить inner.

customers = pd.DataFrame({
    "customer": ["Olena", "Taras", "Iryna", "Maksym", "Sofiia"],
    "segment": ["B2C", "B2C", "B2B", "B2C", "B2B"],
})
orders = pd.read_csv("orders.csv").drop_duplicates()

merged = customers.merge(orders, on="customer", how="left", indicator=True)
print(merged["_merge"].value_counts())
print(merged.loc[merged["_merge"] == "left_only", "customer"].tolist())
_merge
both          9
left_only     1
right_only    0
Name: count, dtype: int64
['Sofiia']

Параметр indicator=True додає стовпець, який показує, чи знайшлася пара для рядка, — так знаходять клієнтів без замовлень. Що хочуть почути: що після об'єднання ви перевіряєте кількість рядків. Якщо ключ у правій таблиці не унікальний, рядки розмножуються і суми завищуються; захиститися допомагає параметр validate, наприклад validate="one_to_many" (настанова з merge).

Як ви працюєте з пропущеними значеннями?

Спершу рахую їх і з'ясовую причину, потім обираю одне з трьох: залишити, видалити рядки або заповнити. Універсального правильного варіанта немає — він залежить від того, що означає пропуск.

df = pd.read_csv("orders.csv").drop_duplicates()

print(df["amount"].mean())            # NaN is skipped
print(df["amount"].fillna(0).mean())  # NaN counted as 0
print(len(df.dropna(subset=["amount"])))
df["city"] = df["city"].fillna("Unknown")
print(df["city"].value_counts())
900.0
800.0
8
city
Kyiv       6
Lviv       2
Unknown    1
Name: count, dtype: int64

Середній чек 900 або 800 — залежить від того, чи вважати замовлення без суми нульовим. Агрегатні методи pandas пропуски за замовчуванням оминають, як і SQL. Заповнювати числовий стовпець нулем, середнім або медіаною можна лише з розумінням наслідків: заповнення середнім, наприклад, штучно зменшує розкид. Для категорій чесніше окреме значення «Unknown», як у прикладі. Огляд інструментів — у настанові про пропущені дані.

Питання про продуктові та бізнес-метрики

У блоці метрик перевіряють, чи розумієте ви, що стоїть за числом: як воно рахується, від чого залежить і яке рішення за ним ухвалюють. Формули в компаній різняться, тому у відповіді завжди уточнюйте визначення: що в чисельнику, що в знаменнику і за який період. Сам термін розібрано в глосарії — що таке KPI.

Що таке конверсія і воронка?

Конверсія — частка користувачів, які виконали цільову дію, від тих, хто міг її виконати. Воронка — послідовність кроків до цієї дії з конверсією між сусідніми кроками: перегляд товару, кошик, оплата.

Питання, які треба поставити, перш ніж рахувати: що в знаменнику — користувачі, сесії чи візити; за який термін дія зараховується; чи враховуються користувачі, які потрапили на крок в обхід попереднього. Від відповідей число змінюється в рази. Воронка корисна тим, що показує, на якому кроці губиться найбільше людей, — туди й спрямовують зусилля. Запит для розрахунку воронки є в розділі практичних задач.

Що таке утримання і когортний аналіз?

Утримання (retention) — частка користувачів, які повернулися в продукт через заданий час після першого візиту або покупки. Когорта — група користувачів зі спільною стартовою подією в один період, наприклад усі, хто зареєструвався в березні.

Когортний аналіз порівнює утримання різних когорт: рядки таблиці — місяць реєстрації, стовпці — номер місяця життя, у клітинках — частка активних. Він потрібен, бо загальне середнє по базі приховує зміни: приплив нових користувачів маскує те, що старі йдуть швидше. За когортами видно, чи покращилося утримання після зміни в продукті. Що хочуть почути: уточнення, що вважається поверненням — будь-який візит, цільова дія чи покупка.

Що таке LTV і як його порахувати?

LTV (lifetime value) — дохід або прибуток, який один клієнт приносить компанії за весь час стосунків із нею. Найпростіша оцінка — середній дохід із клієнта за період, помножений на середню кількість періодів, упродовж яких клієнт лишається активним.

На практиці уточнюють три речі. Чи рахують за виручкою, чи за маржею — для рішень про рекламу потрібна маржа. За який горизонт — «за весь час» часто замінюють на 6 або 12 місяців, бо далі даних немає. І за якими когортами — LTV клієнтів із різних каналів може різнитися в рази. Використовують метрику в парі з вартістю залучення клієнта: якщо залучення коштує дорожче, ніж клієнт приносить, зростання збиткове.

Метрика впала на 20 % — як ви будете розбиратися?

Спершу перевірю, що падіння справжнє, потім локалізую його за сегментами і кроками воронки і лише після цього шукатиму причину. Це питання на структуру мислення, тому відповідати варто за кроками.

  1. Дані. Чи не зламався збір подій, завантаження або розрахунок; чи не змінювалося визначення метрики; чи повний останній день.
  2. Масштаб. Різке падіння чи поступове, з якої дати, чи бувало таке раніше — сезонність, свята, день тижня.
  3. Чисельник і знаменник. Що саме змінилося: стало менше покупок чи більше відвідувачів за тих самих покупок.
  4. Сегменти. Платформа, канал залучення, країна, нові користувачі й ті, що повернулися, версія застосунку. Падіння в усіх сегментах і в одному — різні історії.
  5. Воронка. На якому кроці конверсія просіла.
  6. Події. Що сталося цієї дати: реліз, зміна ціни, запуск або зупинка реклами, збій у платіжного партнера.
  7. Висновок. Гіпотеза, чим її підтвердити і що запропонувати.

Типова помилка: одразу називати причину — «мабуть, сезонність» — не перевіривши дані й не звузивши область пошуку.

Питання про комунікацію

Аналітика оцінюють за тим, чи ухвалили за його висновком рішення, тому вміння пояснити результат перевіряють нарівні з технікою. На ці питання відповідають прикладом зі свого проєкту — навчального також.

Як ви презентуєте результати аналізу людям без технічної підготовки?

Починаю з висновку і рекомендації, а не з методики розрахунку. Структура коротка: що ми хотіли дізнатися, що виявили, що це означає для бізнесу і що я пропоную зробити. Методика і застереження йдуть після — для тих, хто захоче перевірити.

Кілька правил, які варто назвати. Один слайд або один графік — одна думка, винесена в заголовок цілим реченням. Терміни замінюю мовою слухача: не «p-value менше за 0,05», а «різниця надто велика, щоб списати її на випадковість». Називаю обмеження: за який період дані, чого в них немає, наскільки надійний висновок. І заздалегідь готую відповідь на питання «і що нам із цим робити?» — без неї аналіз лишається довідкою.

Що ви робите, якщо задача від замовника сформульована нечітко?

Уточнюю, яке рішення людина збирається ухвалити за результатом, і вже від нього визначаю, що рахувати. Прохання «вивантаж продажі за квартал» може означати десять різних таблиць.

Питання, які я ставлю: для чого це потрібно і що зміниться залежно від відповіді; як визначається метрика — наприклад, чи рахувати повернення; за який період і в яких розрізах; у якому вигляді потрібен результат і на коли. Потім коротко письмово фіксую домовленість і, якщо задача велика, показую проміжний результат, щоб не піти вбік. Що хочуть почути: що ви не починаєте рахувати, доки не розумієте питання, і не зникаєте на тиждень, щоб принести не те.

Практичні задачі з розв'язками

Практична частина — це зазвичай одна-три задачі на SQL та іноді одна на pandas або таблиці. Нижче чотири типові задачі на тих самих даних. Перш ніж дивитися розв'язок, спробуйте написати свій. Потренувати основи — SELECT, WHERE, агрегатні функції, GROUP BY і перші JOIN — можна в безкоштовному курсі з SQL; повна програма від SELECT до віконних функцій — на курсі SQL.

Задача 1. Останнє оплачене замовлення кожного клієнта

Вивести для кожного клієнта його останнє оплачене замовлення: ім'я, номер, дату і суму. Класична задача «один рядок на групу» — нумеруємо замовлення клієнта від нового до старого і беремо перше.

WITH ranked AS (
  SELECT o.customer_id, o.id AS order_id, o.order_date, o.amount,
         ROW_NUMBER() OVER (
           PARTITION BY o.customer_id
           ORDER BY o.order_date DESC, o.id DESC
         ) AS rn
  FROM orders AS o
  WHERE o.status = 'paid'
)
SELECT c.name, r.order_id, r.order_date, r.amount
FROM ranked AS r
JOIN customers AS c ON c.id = r.customer_id
WHERE r.rn = 1
ORDER BY c.name;
name   order_id  order_date  amount
-----  --------  ----------  ------
Iryna  9         2026-03-28  300
Olena  8         2026-03-20  800
Taras  3         2026-01-28  450

Другий стовпець сортування o.id DESC робить результат однозначним, якщо в клієнта два замовлення в один день. Розв'язок через MAX(order_date) і GROUP BY повернув би дату, але не решту полів замовлення.

Задача 2. Виручка за місяцями і зростання до попереднього місяця

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

WITH monthly AS (
  SELECT strftime('%Y-%m', order_date) AS month,
         SUM(amount)                   AS revenue
  FROM orders
  WHERE status = 'paid'
  GROUP BY strftime('%Y-%m', order_date)
)
SELECT month, revenue,
       ROUND(
         100.0 * (revenue - LAG(revenue) OVER (ORDER BY month))
               / LAG(revenue) OVER (ORDER BY month),
         1
       ) AS growth_pct
FROM monthly
ORDER BY month;
month    revenue  growth_pct
-------  -------  ----------
2026-01  1650
2026-02  2800     69.7
2026-03  2300     -17.9

Множник 100.0, а не 100, стоїть не випадково: у SQLite і PostgreSQL ділення цілого на ціле відкидає дробову частину, і 2 / 8 дає 0. У MySQL оператор / повертає дробове число, але писати 100.0 — звичка, яка працює всюди.

Задача 3. Конверсія за кроками воронки

Є таблиця подій: перегляд, додавання в кошик, покупка. Порахувати, скільки користувачів дійшло до кожного кроку, і конверсію між кроками.

CREATE TABLE events (
  user_id    INTEGER NOT NULL,
  event      TEXT NOT NULL,
  event_date TEXT NOT NULL
);

INSERT INTO events VALUES
  (1, 'view', '2026-03-01'), (1, 'cart', '2026-03-01'), (1, 'purchase', '2026-03-02'),
  (2, 'view', '2026-03-01'), (2, 'cart', '2026-03-03'),
  (3, 'view', '2026-03-02'),
  (4, 'view', '2026-03-02'), (4, 'view', '2026-03-04'), (4, 'cart', '2026-03-04'), (4, 'purchase', '2026-03-04'),
  (5, 'view', '2026-03-05'),
  (6, 'view', '2026-03-05'), (6, 'cart', '2026-03-06'),
  (7, 'view', '2026-03-06'),
  (8, 'view', '2026-03-07');

WITH funnel AS (
  SELECT COUNT(DISTINCT CASE WHEN event = 'view'     THEN user_id END) AS viewed,
         COUNT(DISTINCT CASE WHEN event = 'cart'     THEN user_id END) AS added_to_cart,
         COUNT(DISTINCT CASE WHEN event = 'purchase' THEN user_id END) AS purchased
  FROM events
)
SELECT viewed, added_to_cart, purchased,
       ROUND(100.0 * added_to_cart / viewed, 1)    AS view_to_cart_pct,
       ROUND(100.0 * purchased / added_to_cart, 1) AS cart_to_purchase_pct,
       ROUND(100.0 * purchased / viewed, 1)        AS view_to_purchase_pct
FROM funnel;
viewed  added_to_cart  purchased  view_to_cart_pct  cart_to_purchase_pct  view_to_purchase_pct
------  -------------  ---------  ----------------  --------------------  --------------------
8       4              2          50.0              50.0                  25.0

Прийом — умовна агрегація: CASE без гілки ELSE повертає NULL для «чужих» подій, а COUNT(DISTINCT ...) порожні значення не рахує. DISTINCT обов'язковий: користувач 4 дивився товар двічі, але у воронці це одна людина. На інтерв'ю варто обумовити припущення: запит рахує тих, у кого подія була, і не перевіряє порядок кроків.

Задача 4. Очистити файл і порахувати показники за місяцями в pandas

Із файлу orders.csv отримати за місяцями кількість оплачених замовлень, виручку і середній чек.

import pandas as pd

df = pd.read_csv("orders.csv", parse_dates=["order_date"])

df = df.drop_duplicates(subset="order_id")           # 1. remove duplicates
df = df.dropna(subset=["amount"])                    # 2. no amount - no revenue
df = df[df["status"] == "paid"]                      # 3. only paid orders
df["month"] = df["order_date"].dt.to_period("M")     # 4. month of the order

monthly = (
    df.groupby("month")
    .agg(orders=("order_id", "count"),
         revenue=("amount", "sum"),
         avg_check=("amount", "mean"))
    .round(1)
)
print(monthly)
         orders  revenue  avg_check
month                              
2026-01       2   1650.0      825.0
2026-02       2   2800.0     1400.0
2026-03       3   2300.0      766.7

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

Типові помилки кандидатів

Більшість помилок на співбесіді аналітика — не прогалини в знаннях, а звичка рахувати, не перевіривши дані й не уточнивши питання. Перелік складено з викладацького досвіду авторки.

  • Писати запит мовчки. Інтерв'юер оцінює хід думки. Проговорюйте: які таблиці, який ключ, скільки рядків очікуєте.
  • Не уточнювати умову. «Виручка» — з поверненнями чи без? «Активний клієнт» — за який термін? Запитання до умови — плюс, а не слабкість.
  • Не перевіряти кількість рядків після JOIN. Розмножені рядки завищують суми, і результат має правдоподібний вигляд.
  • Забувати про NULL. Порожні значення у фільтрах, NOT IN і середніх — джерело більшості «чому не сходиться».
  • Завчати визначення без прикладу. Визначення p-value або контексту фільтра без прикладу звучить як вивчений текст.
  • Називати інструменти замість результату. «Зробив дашборд у Power BI» нічого не каже; «дашборд показав, на якому кроці губляться заявки» — каже.
  • Не знати власний проєкт. Якщо в портфоліо є запит або міра, які ви не можете пояснити, їх краще прибрати.
  • Вигадувати відповідь. Чесне «не знаю, але міркував би так» сприймається краще за впевнену помилку.
  • Не ставити запитань наприкінці. Це читається як відсутність інтересу до роботи.

Що запитати в інтерв'юера?

Запитання кандидата показують, що ви обираєте роботу, а не просто шукаєте будь-яку, і заразом дають зрозуміти, чим ви займатиметеся насправді.

  • Які задачі аналітик розв'язує в перші три місяці? Можна приклад нещодавньої задачі?
  • Де зберігаються дані і хто відповідає за їхню якість — чи є інженери даних і ETL-процеси, чи аналітик збирає все сам?
  • Який стек використовується щодня: СУБД, BI-інструмент, Python?
  • Хто ставить задачі аналітику і який вигляд має типовий запит від бізнесу?
  • Як перевіряється робота: чи є рев'ю запитів і звітів?
  • Скільки в роботі разових вивантажень, а скільки — досліджень і регулярної звітності?
  • Хто буде моїм наставником у перші місяці і як улаштовано введення в роботу?
  • За якими ознаками через пів року ви зрозумієте, що я справляюся?
  • Які наступні етапи відбору і коли чекати відповіді?

План підготовки на два тижні

Двох тижнів по півтори-дві години на день вистачає, щоб повторити базу і натренувати відповіді вголос, — за умови, що теми ви вже вивчали. Це авторський орієнтир, а не норма: якщо SQL або статистика для вас нові, закладіть на них більше часу. Про те, як професія поєднується з AI-інструментами, — у статті AI + Data Analytics.

ДніТемаЩо зробити
1–2SQL: SELECT, WHERE, GROUP BY, HAVINGСтворити таблиці зі статті, написати з пам'яті запити з агрегацією, пояснити вголос порядок виконання
3–4SQL: JOIN, NULL, підзапити і CTEДля кожного JOIN заздалегідь передбачити кількість рядків; знайти клієнтів без замовлень трьома способами
5–6SQL: віконні функціїРанжування, накопичувальний підсумок, LAG; розв'язати задачі 1–3 без підказок
7Повторення SQLРозв'язати три задачі на час, проговорюючи розв'язок уголос
8СтатистикаСвоїми словами, з прикладом: середнє і медіана, розкид, кореляція, p-value, A/B-тест
9Excel або Google SheetsФункції пошуку, зведена таблиця, очищення «брудного» файлу
10Power BI і DAXЗібрати модель «зірка» з двох-трьох таблиць, написати міри з CALCULATE, пояснити результат
11pandas (якщо є у вакансії)Прочитати файл, очистити, згрупувати, об'єднати — задача 4
12МетрикиВизначення конверсії, утримання, LTV; проговорити розслідування падіння метрики
13Проєкти і розповідь про себеДля кожного проєкту: задача, дані, що зробили, результат, що покращили б
14Пробне інтерв'юПопросити знайомого поставити питання зі статті; записати відповіді й переслухати

Блок Power BI і DAX зручніше повторювати на власній моделі, а не за конспектом. Моделі даних, зв'язки, DAX і Power Query з нуля входять до програми курсу Power BI. Хто такий аналітик даних і чим його роль відрізняється від сусідніх, коротко описано в глосарії — Data Analyst.

Часті запитання

Скільки часу потрібно на підготовку до співбесіди на Data Analyst?

Якщо базу ви вже вчили, на повторення і тренування зазвичай вистачає двох тижнів по півтори-дві години на день: тиждень на SQL, тиждень на статистику, BI, метрики та розповідь про проєкти. Це орієнтир авторки як викладача, а не статистика. Якщо SQL і статистику ви ще не вивчали, двох тижнів не вистачить — спершу потрібна сама база.

Чи буде на співбесіді live-coding з SQL?

Найімовірніше, так: написати запит при інтерв'юері або у спільному редакторі — найпоширеніший практичний формат для аналітика. Зазвичай це одна-три задачі на JOIN, GROUP BY і віконні функції. Проговорюйте хід думки вголос і спершу уточнюйте, що вважається одним рядком у таблиці.

Чи потрібна англійська на співбесіді аналітика даних?

Англійська для читання потрібна в будь-якому разі: документація SQL, pandas і Power BI написана англійською. Розмовний рівень перевіряють там, де команда або замовник працюють англійською, — зазвичай короткою частиною інтерв'ю. Вимогу до рівня вказують у вакансії, тож її варто перевірити заздалегідь.

Чи можна користуватися AI-інструментами на співбесіді та в тестовому завданні?

На живому інтерв'ю — лише якщо інтерв'юер прямо дозволив; запитайте про це на початку. У домашньому тестовому завданні правила встановлює компанія: якщо заборони немає, користуватися можна, але кожне рішення доведеться пояснити на розборі. Запит, який ви не можете пояснити, шкодить більше, ніж нерозв'язана задача.

Що робити, якщо не знаєш відповіді на питання?

Сказати про це прямо і показати, як ви міркуєте: що знаєте про суміжну тему, як перевірили б гіпотезу, де подивилися б у документації. Інтерв'юер оцінює хід думки, а не лише готову відповідь. Найгірше — впевнено вигадувати: хибна відповідь упевненим тоном запам'ятовується сильніше, ніж чесне «не знаю».

Чи дають тестове завдання і скільки воно займає?

Часто дають: набір даних і кілька питань бізнесу, на які треба відповісти запитами, розрахунками і коротким висновком або дашбордом. Обсяг у компаній різний, термін і очікуваний час зазвичай указані в самому завданні — якщо ні, уточніть. Оцінюють не лише цифри, а й те, як ви перевірили дані та сформулювали висновки.

Що важливіше для Junior Data Analyst: SQL, Excel чи Power BI?

SQL — його перевіряють практично на кожному технічному інтерв'ю аналітика, бо дані лежать у базах. Excel або Google Sheets і один BI-інструмент потрібні як робочі інструменти для розрахунків і звітів. Точний набір залежить від вакансії, тому перечитайте вимоги і повторіть саме ті інструменти, які в них названі.

Чи потрібен Python аналітику даних-початківцю?

Залежить від вакансії. У багатьох позиціях Junior вистачає SQL, таблиць і BI-інструмента, а Python стоїть у розділі «буде плюсом». Якщо Python указаний у вимогах, чекайте питань про pandas: читання файлу, фільтрація, groupby, merge, пропуски. Упевнений SQL при цьому важливіший за поверхове знання pandas.

Чи потрібне портфоліо для співбесіди на Junior Data Analyst?

Формально його вимагають не завжди, але без комерційного досвіду це головний спосіб показати, що ви вмієте працювати з даними. Достатньо двох-трьох проєктів: SQL-запити до відкритого набору даних, дашборд у Power BI і невеликий аналіз у pandas. Будьте готові пояснити кожне рішення і кожен висновок.

Джерела

Програма курсу Data Analytics →

Фото автора: Олена Булига

Про автора

Тренер Prog Academy з Power BI, викладач вищої школи

Викладач вищої школи: викладала комп’ютерні науки в НТУ та бізнес-аналітику Power BI в університеті КРОК. Співпрацює з бізнесом у сфері аналітики даних; у блозі пише про Power BI, DAX і візуалізацію даних.

Контакт

Записатися на консультацію

Вкажіть актуальний номер, ми зателефонуємо в будь яку країну :)