Определение

WITH позволяет записывать дополнительные операторы для применения в больших запросах. Эти операторы, которые также называют общими табличными выражениями (Common Table Expressions, CTE), можно представить как определения временных таблиц, существующих только для одного запроса.

Дополнительным оператором в предложении WITH может быть SELECT, INSERT, UPDATE или DELETE, а само предложение WITH присоединяется к основному оператору, которым также может быть SELECT, INSERT, UPDATE или DELETE.

Начнем с малого. Посмотрим как с помощью WITH делать подзапросы.

Синтаксис

WITH temp_table_1 AS (
    SELECT ...
),
...
temp_table_N AS (
    SELECT ...
)
SELECT ...
   FROM temp_table_1
             ...            

Пример использования

Возьмем подзапрос определения минимальной и средней цен на товары во фразе FROM:

SELECT *
  FROM (SELECT pp.product_id,
               min (pp.price) AS price_min,
               avg (pp.price) AS price_avg
          FROM product_price pp
         GROUP BY pp.product_id
       ) as ppma
# product_id price_min price_avg
1 1 10500.00 11666.6666666666666667
2 2 26100.00 26800.000000000000
3 3 22000.00 22333.333333333333
4 4 20000.00 21125.000000000000
... ... ... ...

Перепишем с использованием WITH:

WITH product_price_min_avg AS (
  SELECT pp.product_id,
         min (pp.price) AS price_min,
         avg (pp.price) AS price_avg
    FROM product_price pp
   GROUP BY pp.product_id
)
SELECT *
  FROM product_price_min_avg
# product_id price_min price_avg
1 1 10500.00 11666.6666666666666667
2 2 26100.00 26800.000000000000
3 3 22000.00 22333.333333333333
4 4 20000.00 21125.000000000000
... ... ... ...

С помощью WITH большие запросы можно разбивать на части, как бы создавая представления. Например запрос:

SELECT p.product_id,
       p.price_min AS price_min_product,
       i.price_min AS price_min_purchase,
       p.price_avg AS price_avg_product,
       i.price_avg AS price_avg_purchase
  FROM (SELECT pp.product_id,
               min (pp.price) AS price_min,
               avg (pp.price) AS price_avg
          FROM product_price pp
         GROUP BY pp.product_id
       ) p,
       (SELECT pi.product_id,
               min (pi.price) AS price_min,
               avg (pi.price) AS price_avg
          FROM purchase_item pi
         GROUP BY pi.product_id
       ) i
 WHERE i.product_id = p.product_id
 ORDER BY p.product_id
# product_id price_min_product price_min_purchase price_avg_product price_avg_purchase
1 2 26100.00 26100.00 26800.000000000000 26800.000000000000
2 3 22000.00 26100.00 22333.333333333333 26100.000000000000
3 4 20000.00 21500.00 21125.000000000000 21500.000000000000
... ... ... ... ... ...

можно переписать так:

WITH product_price_min_avg AS (
  SELECT pp.product_id,
         min (pp.price) AS price_min,
         avg (pp.price) AS price_avg
    FROM product_price pp
   GROUP BY pp.product_id
),
purchase_price_min_avg AS (
  SELECT pi.product_id,
         min (pi.price) AS price_min,
         avg (pi.price) AS price_avg
    FROM purchase_item pi
   GROUP BY pi.product_id
)
SELECT p.product_id,
       p.price_min AS price_min_product,
       i.price_min AS price_min_purchase,
       p.price_avg AS price_avg_product,
       i.price_avg AS price_avg_purchase
  FROM product_price_min_avg p,
       purchase_price_min_avg i
 WHERE i.product_id = p.product_id
 ORDER BY p.product_id
# product_id price_min_product price_min_purchase price_avg_product price_avg_purchase
1 2 26100.00 26100.00 26800.000000000000 26800.000000000000
2 3 22000.00 26100.00 22333.333333333333 26100.000000000000
3 4 20000.00 21500.00 21125.000000000000 21500.000000000000
... ... ... ... ... ...

Основная часть запроса выглядит просто

SELECT p.product_id,
       p.price_min AS price_min_product,
       i.price_min AS price_min_purchase,
       p.price_avg AS price_avg_product,
       i.price_avg AS price_avg_purchase
  FROM product_price_min_avg p,
       purchase_price_min_avg i
 WHERE i.product_id = p.product_id
 ORDER BY p.product_id

Логику по вычислению минимальной и средней цены мы спрятали в product_price_min_avg и purchase_price_min_avg.

На product_price_min_avg и purchase_price_min_avg можно смотреть как на представления в SQL, но только для одного запроса. Или как на функции в других языках программирования.

10.1 Подзапрос во фразе FROM

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