# Продуктивное учебное задание № 5  «Однотабличные запросы»

База данных:

* `users(user_id, full_name, username, paid, vpn_date, vpn_uuid, timestamp)`
* `lessons(id, title, description)`
* `user_lessons(user_id, lesson_number, completed, timestamp)`
* `homeworks(id, user_id, lesson_number, homework_text, completed, timestamp)`
* `questions(id, user_id, question_text, answered, timestamp)`
* `reviews(id, user_id, review_text, rating, timestamp)`
* `slots(id, date, time, booked_by, reminded)`

Примечание: ниже даны запросы в синтаксисе **MySQL 8+**.

### 1) Однотабличные запросы (>= 18)

#### а) Выборка всех столбцов из таблицы (2)

```sql
-- Q1
SELECT * FROM users;

-- Q2
SELECT * FROM homeworks;
```

#### б) Выборка некоторых столбцов (2)

```sql
-- Q3
SELECT user_id, full_name, paid FROM users;

-- Q4
SELECT id, title FROM lessons;
```

#### в) Выборка без повторяющихся строк (DISTINCT) (2)

```sql
-- Q5
SELECT DISTINCT paid FROM users;

-- Q6
SELECT DISTINCT lesson_number FROM user_lessons;
```

#### г) Выборка с вычисляемыми полями (2)

```sql
-- Q7
SELECT user_id,
       full_name,
       CASE WHEN paid = 1 THEN 'Оплачен' ELSE 'Не оплачен' END AS paid_status
FROM users;

-- Q8
SELECT id,
       rating,
       rating * 20 AS rating_percent
FROM reviews;
```

#### д) Выборка с сортировкой (2)

```sql
-- Q9
SELECT user_id, full_name, `timestamp`
FROM users
ORDER BY full_name ASC;

-- Q10
SELECT id, `date`, `time`
FROM slots
ORDER BY `date` DESC, `time` DESC;
```

#### е) Объединение нескольких запросов (UNION/UNION ALL) (2)

```sql
-- Q11
SELECT full_name AS item, 'user' AS source
FROM users
UNION
SELECT title AS item, 'lesson' AS source
FROM lessons;

-- Q12
SELECT user_id AS actor_id, `timestamp` AS event_time, 'homework' AS event_type
FROM homeworks
UNION ALL
SELECT user_id AS actor_id, `timestamp` AS event_time, 'question' AS event_type
FROM questions;
```

#### ж) Выборка с условием отбора (2)

```sql
-- Q13
SELECT user_id, full_name, vpn_date
FROM users
WHERE paid = 1;

-- Q14
SELECT id, user_id, question_text
FROM questions
WHERE answered = 0;
```

#### з) Итоговый запрос (GROUP BY, агрегаты) (2)

```sql
-- Q15
SELECT paid, COUNT(*) AS users_count
FROM users
GROUP BY paid;

-- Q16
SELECT user_id, COUNT(*) AS questions_count
FROM questions
GROUP BY user_id;
```

#### и) Итоговый запрос с условием отбора групп (HAVING) (2)

```sql
-- Q17
SELECT user_id, COUNT(*) AS hw_count
FROM homeworks
GROUP BY user_id
HAVING COUNT(*) >= 2;

-- Q18
SELECT lesson_number, COUNT(*) AS completed_count
FROM user_lessons
WHERE completed = 1
GROUP BY lesson_number
HAVING COUNT(*) >= 1;
```

Итого однотабличных запросов: **18**.

### 2) Многотабличные запросы (>= 10)

#### а) Объединение через условие отбора (неявное join через WHERE) (2)

```sql
-- M1
SELECT u.user_id, u.full_name, q.question_text
FROM users u, questions q
WHERE u.user_id = q.user_id;

-- M2
SELECT u.user_id, u.full_name, r.rating
FROM users u, reviews r
WHERE u.user_id = r.user_id;
```

#### б) Внутреннее объединение (INNER JOIN) (3)

```sql
-- M3
SELECT u.full_name, ul.lesson_number, ul.completed
FROM users u
INNER JOIN user_lessons ul ON u.user_id = ul.user_id;

-- M4
SELECT u.full_name, h.homework_text, h.completed
FROM users u
INNER JOIN homeworks h ON u.user_id = h.user_id;

-- M5
SELECT u.full_name, s.`date`, s.`time`
FROM users u
INNER JOIN slots s ON u.user_id = s.booked_by;
```

#### в) Внешнее объединение левое и правое (4)

```sql
-- M6 LEFT JOIN: все пользователи, даже без вопросов
SELECT u.user_id, u.full_name, q.question_text
FROM users u
LEFT JOIN questions q ON u.user_id = q.user_id;

-- M7 LEFT JOIN: все уроки, даже если никто не назначен
SELECT l.id, l.title, ul.user_id
FROM lessons l
LEFT JOIN user_lessons ul ON l.id = ul.lesson_number;

-- M8 RIGHT JOIN: все отзывы, даже если пользователь удален/не найден
SELECT u.full_name, r.review_text, r.rating
FROM users u
RIGHT JOIN reviews r ON u.user_id = r.user_id;

-- M9 RIGHT JOIN: все слоты, даже если booked_by не сопоставился
SELECT u.full_name, s.`date`, s.`time`, s.booked_by
FROM users u
RIGHT JOIN slots s ON u.user_id = s.booked_by;
```

#### г) Запрос на объединение 3 таблиц (2)

```sql
-- M10
SELECT u.full_name,
       l.title,
       ul.completed,
       ul.`timestamp`
FROM users u
JOIN user_lessons ul ON u.user_id = ul.user_id
JOIN lessons l ON l.id = ul.lesson_number;

-- M11
SELECT u.full_name,
       l.title,
       h.homework_text,
       h.completed
FROM homeworks h
JOIN users u ON u.user_id = h.user_id
JOIN lessons l ON l.id = h.lesson_number;
```

Итого многотабличных запросов: **11**.

### 3) Запросы на изменение данных (>= 12)

#### а) Обновление всех строк (2)

```sql
-- C1
UPDATE questions
SET answered = 0;

-- C2
UPDATE slots
SET reminded = 0;
```

#### б) Обновление с условием отбора (2)

```sql
-- C3
UPDATE users
SET paid = 1
WHERE vpn_uuid IS NOT NULL;

-- C4
UPDATE homeworks
SET completed = 1
WHERE homework_text IS NOT NULL AND LENGTH(homework_text) > 0;
```

#### в) Обновление 3 таблиц (2 комплекта)

```sql
-- C5: комплект обновлений №1 (в транзакции)
BEGIN;
UPDATE users SET paid = 0 WHERE vpn_date < CURRENT_DATE();
UPDATE slots SET reminded = 1 WHERE `date` = CURRENT_DATE();
UPDATE questions SET answered = 1 WHERE `timestamp` < (CURRENT_DATE() - INTERVAL 30 DAY);
COMMIT;

-- C6: комплект обновлений №2 (в транзакции)
BEGIN;
UPDATE user_lessons SET completed = 1 WHERE lesson_number = 1;
UPDATE homeworks SET completed = 1 WHERE lesson_number = 1;
UPDATE reviews SET rating = 5 WHERE rating > 5;
COMMIT;
```

#### г) Удаление всех строк (2)

```sql
-- C7
DELETE FROM reviews;

-- C8
DELETE FROM questions;
```

#### д) Удаление с условием отбора (2)

```sql
-- C9
DELETE FROM slots
WHERE booked_by IS NULL;

-- C10
DELETE FROM homeworks
WHERE completed = 0;
```

#### е) Удаление с подчиненным запросом (2)

```sql
-- C11
DELETE FROM users
WHERE user_id IN (
    SELECT x.user_id
    FROM (
        SELECT u.user_id
        FROM users u
        LEFT JOIN user_lessons ul ON u.user_id = ul.user_id
        WHERE ul.user_id IS NULL
    ) AS x
);

-- C12
DELETE FROM lessons
WHERE id NOT IN (
    SELECT DISTINCT lesson_number
    FROM user_lessons
);
```

Итого запросов на изменение данных: **12**.

### 4) Обоснование выбора итоговых запросов для отчетов

Для построения итоговых отчетов выбраны агрегатные запросы:

* `Q15` (распределение пользователей по оплате) — основа отчета «Платежная дисциплина».
* `Q16` (количество вопросов по пользователям) — основа отчета «Нагрузка поддержки».
* `Q17` (пользователи с >= 2 ДЗ) — основа отчета «Активность по домашним заданиям».
* `Q18` (количество завершений по урокам) — основа отчета «Прогресс по урокам».

Эти запросы выбраны, потому что:

1. Покрывают ключевые KPI предметной области: оплата, активность, завершение обучения, нагрузка по вопросам.
2. Используют группировку и условие по группам (`HAVING`), что соответствует требованиям итоговой отчетности.
3. Являются масштабируемыми: можно добавлять фильтрацию по периоду, пользователю, статусу.

### 5) Проверка критериев

1. Количество запросов соответствует требованиям:

* Однотабличные: 18 (минимум 18) — выполнено.
* Многотабличные: 11 (минимум 10) — выполнено.
* На изменение данных: 12 (минимум 12) — выполнено.

2. Правильность выполнения:

* Во всех запросах использованы корректные операторы соответствующего типа (`SELECT`, `JOIN`, `GROUP BY`, `HAVING`, `UPDATE`, `DELETE`, подзапросы).

3. Обоснование итоговых отчетов:

* Выбор итоговых запросов описан в разделе 4.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://letas-organization.gitbook.io/letaats-lessons-online/untitled-1/bazy-dannykh/produktivnoe-uchebnoe-zadanie-5-odnotablichnye-zaprosy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
