Определение
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, но только для одного запроса. Или как на функции в других языках программирования.