Несколько подзапросов в WITH

Посмотрим на решение задания про сотрудников, которые продали меньше, чем среднестатистический сотрудник.

В запросе

WITH employee_result AS (
  SELECT p.employee_id,
         sum (pi.price * pi.count) AS sum_purchases
    FROM purchase p,
         purchase_item pi
   WHERE pi.purchase_id = p.purchase_id
     AND p.employee_id IS NOT NULL
   GROUP BY p.employee_id
)
SELECT er.employee_id,
       e.last_name,
       e.first_name,
       er.sum_purchases
  FROM employee_result er,
       employee e
 WHERE e.employee_id = er.employee_id
   AND er.sum_purchases < (SELECT avg (ern.sum_purchases)
                             FROM employee_result ern)
 ORDER BY er.sum_purchases,
          er.employee_id

мы ссылаемся на таблицу employee_result дважды: во фразе FROM и в подзапросе

(SELECT avg (ern.sum_purchases)
   FROM employee_result ern)

Это очень удобно. Один раз написал и используешь сколько нужно.

Несколько подзапросов

Пойдем дальше в анализе продаж сотрудниками. Добавим в результат сумму продаж по каждому магазину.

WITH employee_result AS (
  SELECT p.employee_id,
         p.store_id,
         sum (pi.price * pi.count) AS sum_purchases
    FROM purchase p,
         purchase_item pi
   WHERE pi.purchase_id = p.purchase_id
     AND p.employee_id IS NOT NULL
   GROUP BY p.employee_id,
            p.store_id
),
store_result AS (
  SELECT er.store_id,
         sum (er.sum_purchases) AS sum_purchases
    FROM employee_result er
   GROUP BY er.store_id
)
SELECT s.name AS store_name,
       e.last_name,
       e.first_name,
       er.sum_purchases AS sum_purchases_employee,
       sr.sum_purchases AS sum_purchases_store
  FROM employee_result er,
       store_result sr,
       employee e,
       store s
 WHERE sr.store_id = er.store_id
   AND e.employee_id = er.employee_id
   AND s.store_id = er.store_id
 ORDER BY s.name,
          er.sum_purchases
# store_name last_name first_name sum_purchases_employee sum_purchases_store
1 Big Громов Юлиан 1321800000.00 1321800000.00
2 Umi Агафьев Мирон 158800.00 411300.00
3 Umi Белозёров Зиновий 252500.00 411300.00
4 Адалин-family Суханов Влас 4900.00 4900.00
5 Март Картман Эрик 47000.00 847800.00
6 Март Миронова Зарина 800800.00 847800.00
7 Пионер Блинова Любовь 52200.00 52200.00
8 Сатурн Корсаков Петр 121500.00 121500.00

После подзапроса employee_result в WITH появился еще один подзапрос

store_result AS (
  SELECT er.store_id,
         sum (er.sum_purchases) AS sum_purchases
    FROM employee_result er
   GROUP BY er.store_id
)

Стоит отметить, что в WITH:

  1. Можно писать несколько подзапросов.
  2. Использовать выше определенные подзапросы вместо таблиц.

В основном запросе

SELECT s.name AS store_name,
       e.last_name,
       e.first_name,
       er.sum_purchases AS sum_purchases_employee,
       sr.sum_purchases AS sum_purchases_store
  FROM employee_result er,
       store_result sr,
       employee e,
       store s
 WHERE sr.store_id = er.store_id
   AND e.employee_id = er.employee_id
   AND s.store_id = er.store_id
 ORDER BY s.name,
          er.sum_purchases

Используется и employee_result, и store_result.

Разработка запроса

С использованием WITH очень удобно разрабатывать запрос с несколькими подзапросами.

Например, в запросе

WITH employee_result AS (
  SELECT p.employee_id,
         p.store_id,
         sum (pi.price * pi.count) AS sum_purchases
    FROM purchase p,
         purchase_item pi
   WHERE pi.purchase_id = p.purchase_id
     AND p.employee_id IS NOT NULL
   GROUP BY p.employee_id,
            p.store_id
),
store_result AS (
  SELECT er.store_id,
         sum (er.sum_purchases) AS sum_purchases
    FROM employee_result er
   GROUP BY er.store_id
)
SELECT s.name AS store_name,
       e.last_name,
       e.first_name,
       er.sum_purchases AS sum_purchases_employee,
       sr.sum_purchases AS sum_purchases_store
  FROM employee_result er,
       store_result sr,
       employee e,
       store s
 WHERE sr.store_id = er.store_id
   AND e.employee_id = er.employee_id
   AND s.store_id = er.store_id
 ORDER BY s.name,
          er.sum_purchases

посмотрим, что возвращает каждый подзапрос. Для этого комментируем (или удаляем, мы для краткости удалим) основной запрос и оставляем SELECT * из интересующего подзапроса.

Посморим, что в employee_result:

WITH employee_result AS (
  SELECT p.employee_id,
         p.store_id,
         sum (pi.price * pi.count) AS sum_purchases
    FROM purchase p,
         purchase_item pi
   WHERE pi.purchase_id = p.purchase_id
     AND p.employee_id IS NOT NULL
   GROUP BY p.employee_id,
            p.store_id
),
store_result AS (
  SELECT er.store_id,
         sum (er.sum_purchases) AS sum_purchases
    FROM employee_result er
   GROUP BY er.store_id
)
SELECT *
  FROM employee_result
# employee_id store_id sum_purchases
1 25 100 52200.00
2 8 201 121500.00
3 43 301 4900.00
4 29 500 800800.00
5 15 500 47000.00
... ... ... ...

Что в store_result:

WITH employee_result AS (
  SELECT p.employee_id,
         p.store_id,
         sum (pi.price * pi.count) AS sum_purchases
    FROM purchase p,
         purchase_item pi
   WHERE pi.purchase_id = p.purchase_id
     AND p.employee_id IS NOT NULL
   GROUP BY p.employee_id,
            p.store_id
),
store_result AS (
  SELECT er.store_id,
         sum (er.sum_purchases) AS sum_purchases
    FROM employee_result er
   GROUP BY er.store_id
)
SELECT *
  FROM store_result
# store_id sum_purchases
1 100 52200.00
2 201 121500.00
3 301 4900.00
4 500 847800.00
... ... ...

10.2 Введение в WITH

10.4 Простейший рекурсивный запрос