Условие
В таблице friend_request(sender_id, receiver_id, sent_date) лежат отправленные запросы в друзья. В таблице request_accepted(requester_id, accepter_id, accepted_date) — принятые. Посчитайте общий показатель «доля принятых» — отношение числа принятых уникальных пар (sender → receiver) к числу отправленных. Учтите, что одну и ту же пару можно отправить несколько раз.
Решение
Подход
Сначала сводим запросы к уникальным парам (sender, receiver) через COUNT(DISTINCT ...). То же — для принятых: одна пара = один accept. Считаем отношение.
Реализация
SELECT
ROUND(
COALESCE(
(SELECT COUNT(DISTINCT requester_id || '-' || accepter_id)
FROM request_accepted)::float
/
NULLIF(
(SELECT COUNT(DISTINCT sender_id || '-' || receiver_id)
FROM friend_request), 0
),
0
)::numeric,
4
) AS acceptance_rate;Более чистая версия через CTE:
WITH sent AS (
SELECT DISTINCT sender_id, receiver_id FROM friend_request
),
accepted AS (
SELECT DISTINCT requester_id, accepter_id FROM request_accepted
)
SELECT
ROUND(
(SELECT COUNT(*) FROM accepted)::numeric
/ NULLIF((SELECT COUNT(*) FROM sent), 0),
4
) AS acceptance_rate;Подводные камни
- Несколько запросов от одной пары. Без
DISTINCTпосчитаете одну и ту же дружбу 5 раз и завысите знаменатель. - Несовпадение названий колонок: в
request_acceptedпара называется(requester_id, accepter_id), а не(sender_id, receiver_id). На собеседовании путаются и считают по «не той стороне». - Целочисленное деление. В Postgres/MySQL без приведения к
numeric/floatполучите 0. Всегда::numericили* 1.0. - Direction: одна пара (A→B) ≠ (B→A). Если бизнес-смысл «дружба», нужно нормализовать пару:
LEAST(a, b), GREATEST(a, b).
Эталонный ответ
COUNT(DISTINCT pair) по принятым / COUNT(DISTINCT pair) по отправленным. Защититься от деления на ноль и привести к numeric. Если задача про «дружбу», нормализовать направление пары.