Ответы к заданиям практикума

Эталонные запросы и результаты на учебной базе стенда. Раскрывайте по одному после того, как попробовали сами.

Открыть редактор запросов ↗   Задания   Таблицы и схема   Шпаргалка SQL   Ответы

Эталонные запросы и результаты на учебной базе registry.sqlite. Запросы работают в SQLite, PostgreSQL и MySQL 8.

0. Проверка подключения — показать решение
SELECT COUNT(*) AS cases_total FROM cases;

Результат, строк: 1

cases_total
92
1. SELECT, ORDER BY, LIMIT: пять последних обращений — показать решение
SELECT case_id, district_code, opened_at
FROM cases
ORDER BY opened_at DESC, case_id DESC
LIMIT 5;

Результат, строк: 5

case_iddistrict_codeopened_at
1034R-22026-08-28
1024R-32026-08-27
1017R-22026-08-27
1068R-62026-08-24
1051R-52026-08-23
2. WHERE: район R-2, второй квартал — показать решение
SELECT case_id, topic_code, opened_at, channel
FROM cases
WHERE district_code = 'R-2'
  AND opened_at >= '2026-04-01'
  AND opened_at < '2026-07-01'
ORDER BY opened_at;

Результат, строк: 6

case_idtopic_codeopened_atchannel
1072T-22026-04-22телефон
1033T-22026-04-25телефон
1056T-42026-05-31портал
1064T-62026-06-13телефон
1031T-52026-06-27письмо
1050T-42026-06-29письмо
3. WHERE с IS NULL и IN: открытые обращения с портала и по телефону — показать решение
SELECT COUNT(*) AS open_cases
FROM cases
WHERE closed_at IS NULL
  AND channel IN ('портал', 'телефон');

Результат, строк: 1

open_cases
12
4. Агрегаты: всего, закрыто, средний и максимальный срок — показать решение
SELECT COUNT(*) AS cases_total,
       COUNT(closed_at) AS cases_closed,
       ROUND(AVG(days_to_close), 1) AS avg_days,
       MAX(days_to_close) AS max_days
FROM cases;

Результат, строк: 1

cases_totalcases_closedavg_daysmax_days
926813.228
5. GROUP BY и HAVING: районы с 15 и более обращениями — показать решение
SELECT district_code,
       COUNT(*) AS cases_total,
       COUNT(closed_at) AS cases_closed,
       ROUND(AVG(days_to_close), 1) AS avg_days
FROM cases
GROUP BY district_code
HAVING COUNT(*) >= 15
ORDER BY avg_days DESC;

Результат, строк: 4

district_codecases_totalcases_closedavg_days
R-2181017.3
R-3181514.7
R-4191411.6
R-5211610.4
6. GROUP BY по месяцу: динамика регистрации — показать решение
SELECT SUBSTR(opened_at, 1, 7) AS month,
       COUNT(*) AS cases_total
FROM cases
GROUP BY SUBSTR(opened_at, 1, 7)
ORDER BY month;

Результат, строк: 8

monthcases_total
2026-0114
2026-029
2026-037
2026-0413
2026-0515
2026-0612
2026-079
2026-0813
7. LEFT JOIN: обращения по названиям районов — показать решение
SELECT d.title AS district,
       COUNT(c.case_id) AS cases_total
FROM cases AS c
LEFT JOIN districts AS d
  ON c.district_code = d.district_code
GROUP BY d.title
ORDER BY cases_total DESC, district;

Результат, строк: 6

districtcases_total
Нура21
Байконур19
Есиль18
Сарыарка18
Алматы13
3
8. Два объединения: тема и район в одном отчёте — показать решение
SELECT t.title AS topic,
       d.title AS district,
       COUNT(*) AS cases_total
FROM cases AS c
LEFT JOIN topics AS t ON c.topic_code = t.topic_code
LEFT JOIN districts AS d ON c.district_code = d.district_code
WHERE c.topic_code = 'T-2'
GROUP BY t.title, d.title
ORDER BY cases_total DESC, district;

Результат, строк: 5

topicdistrictcases_total
Дороги и транспортЕсиль7
Дороги и транспортБайконур5
Дороги и транспортАлматы3
Дороги и транспортНура3
Дороги и транспортСарыарка2
9. CASE и доля: закрыто в срок (15 дней) по темам — показать решение
SELECT t.title AS topic,
       COUNT(c.closed_at) AS closed_total,
       SUM(CASE WHEN c.days_to_close <= 15 THEN 1 ELSE 0 END) AS closed_on_time,
       ROUND(100.0 * SUM(CASE WHEN c.days_to_close <= 15 THEN 1 ELSE 0 END) / COUNT(c.closed_at), 1) AS on_time_pct
FROM cases AS c
LEFT JOIN topics AS t ON c.topic_code = t.topic_code
GROUP BY t.title
ORDER BY on_time_pct DESC;

Результат, строк: 6

topicclosed_totalclosed_on_timeon_time_pct
Социальная поддержка131292.3
Дороги и транспорт13861.5
ЖКХ и коммунальные услуги10660.0
Образование11654.5
Здравоохранение13753.8
Благоустройство8450.0
10. Подзапрос и CTE: районы со сроком выше среднего — показать решение
WITH by_district AS (
  SELECT district_code, ROUND(AVG(days_to_close), 1) AS avg_days
  FROM cases
  GROUP BY district_code
)
SELECT district_code, avg_days
FROM by_district
WHERE avg_days > (SELECT AVG(days_to_close) FROM cases)
ORDER BY avg_days DESC;

Результат, строк: 3

district_codeavg_days
R-217.3
R-314.7
R-114.0
11. Проверка качества: повтор ИИН в таблице заявителей — показать решение
SELECT iin, COUNT(*) AS persons_with_iin
FROM persons
GROUP BY iin
HAVING COUNT(*) > 1;

Результат, строк: 1

iinpersons_with_iin
6309263000792
12. Проверка качества: код района, которого нет в справочнике — показать решение
SELECT c.case_id, c.district_code
FROM cases AS c
LEFT JOIN districts AS d ON c.district_code = d.district_code
WHERE d.district_code IS NULL
ORDER BY c.case_id;

Результат, строк: 3

case_iddistrict_code
1008R-6
1038R-6
1068R-6
13. Ловушка объединения: справочник с историей без фильтра версии — показать решение
SELECT COUNT(*) AS rows_after_join
FROM cases AS c
JOIN districts_history AS h ON c.district_code = h.district_code;

Результат, строк: 1

rows_after_join
107
14. Ловушка объединения: то же с фильтром актуальной версии — показать решение
SELECT COUNT(*) AS rows_after_join
FROM cases AS c
JOIN districts_history AS h
  ON c.district_code = h.district_code
 AND h.valid_to IS NULL;

Результат, строк: 1

rows_after_join
89
15. Проверка качества: двойная регистрация обращения — показать решение
SELECT person_id, topic_code, opened_at, COUNT(*) AS copies
FROM cases
GROUP BY person_id, topic_code, opened_at
HAVING COUNT(*) > 1
ORDER BY opened_at;

Результат, строк: 2

person_idtopic_codeopened_atcopies
24T-22026-02-142
18T-12026-06-152