Посмотрим на решение задания про сотрудников, которые продали меньше, чем среднестатистический сотрудник.
В запросе
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:
- Можно писать несколько подзапросов.
- Использовать выше определенные подзапросы вместо таблиц.
В основном запросе
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 | 
| ... | ... | ... |