| ÐокÑменÑаÑÐ¸Ñ Ð¿Ð¾ PostgreSQL 9.4.1 | |||
|---|---|---|---|
| ÐÑед. | УÑÐ¾Ð²ÐµÐ½Ñ Ð²ÑÑе | Ðлава 7. ÐапÑоÑÑ | След. |
7.8. ÐапÑоÑÑ WITH (ÐбÑие ÑаблиÑнÑе вÑÑажениÑ)
WITH пÑедоÑÑавлÑÐµÑ ÑпоÑоб запиÑÑваÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе опеÑаÑоÑÑ Ð´Ð»Ñ Ð¿ÑÐ¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² болÑÑÐ¸Ñ Ð·Ð°Ð¿ÑоÑÐ°Ñ . ÐÑи опеÑаÑоÑÑ, коÑоÑÑе Ñакже назÑваÑÑ Ð¾Ð±Ñими ÑаблиÑнÑми вÑÑажениÑми (Common Table Expressions, CTE), можно пÑедÑÑавиÑÑ ÐºÐ°Ðº опÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð²ÑеменнÑÑ ÑаблиÑ, ÑÑÑеÑÑвÑÑÑÐ¸Ñ ÑолÑко Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ запÑоÑа. ÐополниÑелÑнÑм опеÑаÑоÑом в пÑедложении WITH Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ SELECT, INSERT, UPDATE или DELETE, а Ñамо пÑедложение WITH пÑиÑоединÑеÑÑÑ Ðº оÑÐ½Ð¾Ð²Ð½Ð¾Ð¼Ñ Ð¾Ð¿ÐµÑаÑоÑÑ, коÑоÑÑм Ñакже Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ SELECT, INSERT, UPDATE или DELETE.
7.8.1. SELECT в WITH
ÐÑновное пÑедназнаÑение SELECT в пÑедложении WITH заклÑÑаеÑÑÑ Ð² Ñазбиении ÑложнÑÑ Ð·Ð°Ð¿ÑоÑов на пÑоÑÑÑе ÑаÑÑи. ÐапÑимеÑ, запÑоÑ:
WITH regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
), top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
)
SELECT region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;вÑÐ²Ð¾Ð´Ð¸Ñ Ð¸Ñоги по пÑодажам ÑолÑко Ð´Ð»Ñ Ð¿ÐµÑедовÑÑ Ñегионов. ÐÑедложение WITH опÑеделÑÐµÑ Ð´Ð²Ð° дополниÑелÑнÑÑ Ð¾Ð¿ÐµÑаÑоÑа regional_sales и top_regions Ñак, ÑÑо ÑезÑлÑÑÐ°Ñ regional_sales иÑполÑзÑеÑÑÑ Ð² top_regions, а ÑезÑлÑÑÐ°Ñ top_regions иÑполÑзÑеÑÑÑ Ð² оÑновном запÑоÑе SELECT. ÐÑÐ¾Ñ Ð¿ÑÐ¸Ð¼ÐµÑ Ð¼Ð¾Ð¶Ð½Ð¾ бÑло Ð±Ñ Ð¿ÐµÑепиÑаÑÑ Ð±ÐµÐ· WITH, но Ñогда нам понадобÑÑÑÑ Ð´Ð²Ð° ÑÑÐ¾Ð²Ð½Ñ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½ÑÑ Ð¿Ð¾Ð´Ð·Ð°Ð¿ÑоÑов SELECT. ÐоказаннÑм вÑÑе ÑпоÑобом ÑÑо можно ÑделаÑÑ Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ пÑоÑе.
ÐеобÑзаÑелÑное Ñказание RECURSIVE пÑевÑаÑÐ°ÐµÑ WITH из пÑоÑÑого ÑинÑакÑиÑеÑкого ÑдобÑÑва в ÑÑедÑÑво ÑеализаÑии Ñого, ÑÑо невозможно в ÑÑандаÑÑном SQL. ÐÑполÑзÑÑ RECURSIVE, запÑÐ¾Ñ WITH Ð¼Ð¾Ð¶ÐµÑ Ð¾Ð±ÑаÑаÑÑÑÑ Ðº ÑобÑÑÐ²ÐµÐ½Ð½Ð¾Ð¼Ñ ÑезÑлÑÑаÑÑ. ÐÑÐµÐ½Ñ Ð¿ÑоÑÑой пÑимеÑ, ÑÑммиÑÑÑÑий ÑиÑла Ð¾Ñ 1 до 100:
WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
SELECT sum(n) FROM t;РобÑем виде ÑекÑÑÑивнÑй запÑÐ¾Ñ WITH вÑегда запиÑÑваеÑÑÑ ÐºÐ°Ðº не ÑекÑÑÑÐ¸Ð²Ð½Ð°Ñ ÑаÑÑÑ, поÑом UNION (или UNION ALL), а заÑем ÑекÑÑÑÐ¸Ð²Ð½Ð°Ñ ÑаÑÑÑ, где ÑолÑко в ÑекÑÑÑивной ÑаÑÑи можно обÑаÑиÑÑÑÑ Ðº ÑезÑлÑÑаÑÑ Ð·Ð°Ð¿ÑоÑа. Такой запÑÐ¾Ñ Ð²ÑполнÑеÑÑÑ ÑледÑÑÑим обÑазом:
ÐÑÑиÑление ÑекÑÑÑивного запÑоÑа
ÐÑÑиÑлÑеÑÑÑ Ð½Ðµ ÑекÑÑÑÐ¸Ð²Ð½Ð°Ñ ÑаÑÑÑ. ÐÐ»Ñ UNION (но не UNION ALL) оÑбÑаÑÑваÑÑÑÑ Ð´ÑблиÑÑÑÑиеÑÑ ÑÑÑоки. ÐÑе оÑÑавÑиеÑÑ ÑÑÑоки вклÑÑаÑÑÑÑ Ð² ÑезÑлÑÑÐ°Ñ ÑекÑÑÑивного запÑоÑа и Ñакже помеÑаÑÑÑÑ Ð²Ð¾ вÑеменнÑÑ ÑабоÑÑÑ ÑаблиÑÑ.
Ðока ÑабоÑÐ°Ñ ÑаблиÑа не пÑÑÑа, повÑоÑÑÑÑÑÑ ÑледÑÑÑие дейÑÑвиÑ:
ÐÑÑиÑлÑеÑÑÑ ÑекÑÑÑÐ¸Ð²Ð½Ð°Ñ ÑаÑÑÑ Ñак, ÑÑо ÑекÑÑÑÐ¸Ð²Ð½Ð°Ñ ÑÑÑлка на Ñам запÑÐ¾Ñ Ð¾Ð±ÑаÑаеÑÑÑ Ðº ÑекÑÑÐµÐ¼Ñ ÑодеÑÐ¶Ð¸Ð¼Ð¾Ð¼Ñ ÑабоÑей ÑаблиÑÑ. ÐÐ»Ñ UNION (но не UNION ALL) оÑбÑаÑÑваÑÑÑÑ Ð´ÑблиÑÑÑÑиеÑÑ ÑÑÑоки и ÑÑÑоки, дÑблиÑÑÑÑие Ñанее полÑÑеннÑе. ÐÑе оÑÑавÑиеÑÑ ÑÑÑоки вклÑÑаÑÑÑÑ Ð² ÑезÑлÑÑÐ°Ñ ÑекÑÑÑивного запÑоÑа и Ñакже помеÑаÑÑÑÑ Ð²Ð¾ вÑеменнÑÑ Ð¿ÑомежÑÑоÑнÑÑ ÑаблиÑÑ.
СодеÑжимое ÑабоÑей ÑаблиÑÑ Ð·Ð°Ð¼ÐµÐ½ÑеÑÑÑ ÑодеÑжимÑм пÑомежÑÑоÑной ÑаблиÑÑ, а заÑем пÑомежÑÑоÑÐ½Ð°Ñ ÑаблиÑа оÑиÑаеÑÑÑ.
ÐамеÑание: СÑÑого говоÑÑ, ÑÑÐ¾Ñ Ð¿ÑоÑеÑÑ ÑвлÑеÑÑÑ Ð¸ÑеÑаÑионнÑм, а не ÑекÑÑÑивнÑм, но комиÑеÑом по ÑÑандаÑÑам SQL бÑл вÑбÑан ÑеÑмин RECURSIVE.
Рпоказанном вÑÑе пÑимеÑе в ÑабоÑей ÑаблиÑе на каждом ÑÑапе ÑодеÑжиÑÑÑ Ð²Ñего одна ÑÑÑока и в ней поÑледоваÑелÑно накапливаÑÑÑÑ Ð·Ð½Ð°ÑÐµÐ½Ð¸Ñ Ð¾Ñ 1 до 100. Ðа ÑоÑом Ñаге, благодаÑÑ ÑÑÐ»Ð¾Ð²Ð¸Ñ WHERE, не возвÑаÑаеÑÑÑ Ð½Ð¸Ñего, Ñак ÑÑо вÑÑиÑление запÑоÑа завеÑÑаеÑÑÑ.
РекÑÑÑивнÑе запÑоÑÑ Ð¾Ð±ÑÑно пÑименÑÑÑÑÑ Ð´Ð»Ñ ÑабоÑÑ Ñ Ð¸ÐµÑаÑÑ Ð¸ÑеÑкими или дÑевовиднÑми ÑÑÑÑкÑÑÑами даннÑÑ . РкаÑеÑÑве полезного пÑимеÑа можно пÑивеÑÑи запÑоÑ, Ð½Ð°Ñ Ð¾Ð´ÑÑий вÑе непоÑÑедÑÑвеннÑе и коÑвеннÑе ÑоÑÑавнÑе ÑаÑÑи пÑодÑкÑа, иÑполÑзÑÑ ÑолÑко ÑаблиÑÑ Ñ Ð¿ÑÑмÑми ÑвÑзÑми:
WITH RECURSIVE included_parts(sub_part, part, quantity) AS (
SELECT sub_part, part, quantity FROM parts WHERE part = 'our_product'
UNION ALL
SELECT p.sub_part, p.part, p.quantity
FROM included_parts pr, parts p
WHERE p.part = pr.sub_part
)
SELECT sub_part, SUM(quantity) as total_quantity
FROM included_parts
GROUP BY sub_partРабоÑÐ°Ñ Ñ ÑекÑÑÑивнÑми запÑоÑами, важно обеÑпеÑиÑÑ, ÑÑÐ¾Ð±Ñ ÑекÑÑÑÐ¸Ð²Ð½Ð°Ñ ÑаÑÑÑ Ð·Ð°Ð¿ÑоÑа в конÑе конÑов не вÑдала Ð½Ð¸ÐºÐ°ÐºÐ¸Ñ ÐºÐ¾ÑÑежей (ÑÑÑок), в пÑоÑивном ÑлÑÑае Ñикл бÑÐ´ÐµÑ Ð±ÐµÑконеÑнÑм. Ðногда Ð´Ð»Ñ ÑÑого доÑÑаÑоÑно пÑименÑÑÑ UNION вмеÑÑо UNION ALL, Ñак как пÑи ÑÑом бÑдÑÑ Ð¾ÑбÑаÑÑваÑÑÑÑ ÑÑÑоки, коÑоÑÑе Ñже еÑÑÑ Ð² ÑезÑлÑÑаÑе. Ðднако ÑаÑÑо в Ñикле вÑдаÑÑÑÑ ÑÑÑоки, не ÑовпадаÑÑие полноÑÑÑÑ Ñ Ð¿ÑедÑдÑÑими: в ÑÐ°ÐºÐ¸Ñ ÑлÑÑаÑÑ Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ ÑмÑÑл пÑовеÑиÑÑ Ð¾Ð´Ð½Ð¾ или неÑколÑко полей, ÑÑÐ¾Ð±Ñ Ð¾Ð¿ÑеделиÑÑ, не бÑла ли ÑекÑÑÐ°Ñ ÑоÑка доÑÑигнÑÑа ÑанÑÑе. СÑандаÑÑнÑй ÑпоÑоб ÑеÑÐµÐ½Ð¸Ñ Ð¿Ð¾Ð´Ð¾Ð±Ð½ÑÑ Ð·Ð°Ð´Ð°Ñ — вÑÑиÑлиÑÑ Ð¼Ð°ÑÑив Ñ Ñже обÑабоÑаннÑми знаÑениÑми. ÐапÑимеÑ, ÑаÑÑмоÑÑиÑе ÑледÑÑÑий запÑоÑ, пÑоÑмаÑÑиваÑÑий ÑаблиÑÑ graph по Ð¿Ð¾Ð»Ñ link:
WITH RECURSIVE search_graph(id, link, data, depth) AS (
SELECT g.id, g.link, g.data, 1
FROM graph g
UNION ALL
SELECT g.id, g.link, g.data, sg.depth + 1
FROM graph g, search_graph sg
WHERE g.id = sg.link
)
SELECT * FROM search_graph;ÐÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ Ð·Ð°ÑиклиÑÑÑ, еÑли ÑвÑзи link ÑодеÑÐ¶Ð°Ñ ÑиклÑ. Так как нам нÑжно полÑÑаÑÑ Ð² ÑезÑлÑÑаÑе "depth", одно лиÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ UNION ALL на UNION не Ð¿Ð¾Ð·Ð²Ð¾Ð»Ð¸Ñ Ð¸Ð·Ð±ÐµÐ¶Ð°ÑÑ Ð·Ð°ÑикливаниÑ. ÐмеÑÑо ÑÑого Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ ÐºÐ°Ðº-Ñо опÑеделиÑÑ, ÑÑо Ñже доÑÑигали ÑекÑÑей ÑÑÑоки, пÑÐ¾Ð¹Ð´Ñ Ð½ÐµÐºÐ¾ÑоÑÑй пÑÑÑ. ÐÐ»Ñ ÑÑого Ð¼Ñ Ð´Ð¾Ð±Ð°Ð²Ð»Ñем две колонки path и cycle и полÑÑаем запÑоÑ, заÑиÑÑннÑй Ð¾Ñ Ð·Ð°ÑикливаниÑ:
WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (
SELECT g.id, g.link, g.data, 1,
ARRAY[g.id],
false
FROM graph g
UNION ALL
SELECT g.id, g.link, g.data, sg.depth + 1,
path || g.id,
g.id = ANY(path)
FROM graph g, search_graph sg
WHERE g.id = sg.link AND NOT cycle
)
SELECT * FROM search_graph;Ðомимо пÑедоÑвÑаÑÐµÐ½Ð¸Ñ Ñиклов, знаÑÐµÐ½Ð¸Ñ Ð¼Ð°ÑÑива ÑаÑÑо бÑваÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ Ñами по Ñебе Ð´Ð»Ñ Ð¿ÑедÑÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ "пÑÑи", пÑиведÑего к опÑеделÑнной ÑÑÑоке.
РобÑем ÑлÑÑае, когда Ð´Ð»Ñ Ð²ÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñикла нÑжно пÑовеÑÑÑÑ Ð½ÐµÑколÑко полей, ÑледÑÐµÑ Ð¸ÑполÑзоваÑÑ Ð¼Ð°ÑÑив ÑÑÑок. ÐапÑимеÑ, еÑли нÑжно ÑÑавниÑÑ Ð¿Ð¾Ð»Ñ f1 и f2:
WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (
SELECT g.id, g.link, g.data, 1,
ARRAY[ROW(g.f1, g.f2)],
false
FROM graph g
UNION ALL
SELECT g.id, g.link, g.data, sg.depth + 1,
path || ROW(g.f1, g.f2),
ROW(g.f1, g.f2) = ANY(path)
FROM graph g, search_graph sg
WHERE g.id = sg.link AND NOT cycle
)
SELECT * FROM search_graph;ÐодÑказка: ЧаÑÑо Ð´Ð»Ñ ÑаÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ Ñикла доÑÑаÑоÑного одного Ð¿Ð¾Ð»Ñ Ð¸ Ñогда ROW() можно опÑÑÑиÑÑ. ÐÑи ÑÑом бÑÐ´ÐµÑ Ð¸ÑполÑзоваÑÑÑÑ Ð½Ðµ маÑÑив даннÑÑ ÑоÑÑавного Ñипа, а пÑоÑÑой маÑÑив, ÑÑо более ÑÑÑекÑивно.
ÐодÑказка: ÐÑÐ¾Ñ Ð°Ð»Ð³Ð¾ÑиÑм ÑекÑÑÑивного вÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑоÑа вÑдаÑÑ Ð² ÑезÑлÑÑаÑе ÑзлÑ, ÑпоÑÑдоÑеннÑе по пÑÑи погÑÑжениÑ. ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ ÑезÑлÑÑаÑÑ, оÑÑоÑÑиÑованнÑе по глÑбине, можно добавиÑÑ Ð²Ð¾ внеÑний запÑÐ¾Ñ ORDER BY по колонке "path", полÑÑенной, как показано вÑÑе.
ÐÐ»Ñ ÑеÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð·Ð°Ð¿ÑоÑов, коÑоÑÑе могÑÑ Ð·Ð°ÑикливаÑÑÑÑ, еÑÑÑ Ñ Ð¾ÑоÑий пÑиÑм — добавиÑÑ LIMIT в ÑодиÑелÑÑкий запÑоÑ. ÐапÑимеÑ, ÑледÑÑÑий запÑÐ¾Ñ Ð·Ð°ÑиклиÑÑÑ, еÑли не добавиÑÑ Ð¿Ñедложение LIMIT:
WITH RECURSIVE t(n) AS (
SELECT 1
UNION ALL
SELECT n+1 FROM t
)
SELECT n FROM t LIMIT 100;Ðо в данном ÑлÑÑае ÑÑого не пÑоиÑÑ Ð¾Ð´Ð¸Ñ, Ñак как в PostgreSQL запÑÐ¾Ñ WITH вÑдаÑÑ ÑÑолÑко ÑÑÑок, ÑколÑко ÑакÑиÑеÑки пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ ÑодиÑелÑÑкий запÑоÑ. РпÑоизводÑÑвенной ÑÑеде иÑполÑзоваÑÑ ÑÑÐ¾Ñ Ð¿ÑиÑм не ÑекомендÑеÑÑÑ, Ñак как дÑÑгие ÑиÑÑÐµÐ¼Ñ Ð¼Ð¾Ð³ÑÑ Ð²ÐµÑÑи ÑÐµÐ±Ñ Ð¿Ð¾-дÑÑгомÑ. ÐÑоме Ñого, ÑÑо не бÑÐ´ÐµÑ ÑабоÑаÑÑ, еÑли внеÑний запÑÐ¾Ñ ÑоÑÑиÑÑÐµÑ ÑезÑлÑÑаÑÑ ÑекÑÑÑивного запÑоÑа или ÑоединÑÐµÑ Ð¸Ñ Ñ Ð´ÑÑгой ÑаблиÑей, Ñак как в подобнÑÑ ÑлÑÑаÑÑ Ð²Ð½ÐµÑний запÑÐ¾Ñ Ð¾Ð±ÑÑно вÑÑ Ñавно вÑбиÑÐ°ÐµÑ ÑезÑлÑÑÐ°Ñ Ð·Ð°Ð¿ÑоÑа WITH полноÑÑÑÑ.
ÐапÑоÑÑ WITH имеÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾Ðµ ÑвойÑÑво — они вÑÑиÑлÑÑÑÑÑ ÑолÑко Ñаз Ð´Ð»Ñ Ð²Ñего ÑодиÑелÑÑкого запÑоÑа, даже еÑли ÑÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ Ð¸Ð»Ð¸ ÑоÑедние запÑоÑÑ WITH обÑаÑаÑÑÑÑ Ðº ним неоднокÑаÑно. Таким обÑазом, ÑложнÑе вÑÑиÑлениÑ, ÑезÑлÑÑаÑÑ ÐºÐ¾ÑоÑÑÑ Ð½ÑÐ¶Ð½Ñ Ð² неÑколÑÐºÐ¸Ñ Ð¼ÐµÑÑÐ°Ñ , можно вÑноÑиÑÑ Ð² запÑоÑÑ WITH в ÑелÑÑ Ð¾Ð¿ÑимизаÑии. ÐÑоме Ñого, Ñакие запÑоÑÑ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÑÑ Ð¸Ð·Ð±ÐµÐ¶Ð°ÑÑ Ð½ÐµÐ¶ÐµÐ»Ð°ÑелÑнÑÑ Ð²ÑÑиÑлений ÑÑнкÑий Ñ Ð¿Ð¾Ð±Ð¾ÑнÑми ÑÑÑекÑами. Ðднако еÑÑÑ Ð¸ обÑаÑÐ½Ð°Ñ ÑÑоÑона — опÑимизаÑÐ¾Ñ Ð½Ðµ Ð¼Ð¾Ð¶ÐµÑ ÑаÑпÑоÑÑÑаниÑÑ Ð¾Ð³ÑаниÑÐµÐ½Ð¸Ñ ÑодиÑелÑÑкого запÑоÑа на запÑÐ¾Ñ WITH Ñак, как он Ð´ÐµÐ»Ð°ÐµÑ ÑÑо Ð´Ð»Ñ Ð¾Ð±ÑÑного подзапÑоÑа. ÐапÑÐ¾Ñ WITH обÑÑно вÑполнÑеÑÑÑ Ð±ÑквалÑно и возвÑаÑÐ°ÐµÑ Ð²Ñе ÑÑÑоки, вклÑÑÐ°Ñ Ñе, ÑÑо поÑом Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑбÑоÑиÑÑ ÑодиÑелÑÑкий запÑоÑ. (Ðо как бÑло Ñказано вÑÑе, вÑÑиÑление Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑановиÑÑÑÑ ÑанÑÑе, еÑли в ÑÑÑлке на ÑÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ Ð·Ð°ÑÑебÑеÑÑÑ ÑолÑко огÑаниÑенное ÑиÑло ÑÑÑок.)
ÐÑимеÑÑ Ð²ÑÑе показÑваÑÑ ÑолÑко пÑедложение WITH Ñ SELECT, но Ñаким же обÑазом его можно иÑполÑзоваÑÑ Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ð¼Ð¸ INSERT, UPDATE и DELETE. Ркаждом ÑлÑÑае он по ÑÑÑи ÑоздаÑÑ Ð²ÑеменнÑÑ ÑаблиÑÑ, к коÑоÑой можно обÑаÑиÑÑÑÑ Ð² оÑновной команде.
7.8.2. Ðзменение даннÑÑ Ð² WITH
РпÑедложении WITH можно Ñакже иÑполÑзоваÑÑ Ð¾Ð¿ÐµÑаÑоÑÑ, изменÑÑÑие даннÑе (INSERT, UPDATE или DELETE). ÐÑо позволÑÐµÑ Ð²ÑполнÑÑÑ Ð² одном запÑоÑе ÑÑÐ°Ð·Ñ Ð½ÐµÑколÑко ÑазнÑÑ Ð¾Ð¿ÐµÑаÑий. ÐапÑимеÑ:
WITH moved_rows AS (
DELETE FROM products
WHERE
"date" >= '2010-10-01' AND
"date" < '2010-11-01'
RETURNING *
)
INSERT INTO products_log
SELECT * FROM moved_rows;ÐÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ ÑакÑиÑеÑки пеÑемеÑÐ°ÐµÑ ÑÑÑоки из products в products_log. ÐпеÑаÑÐ¾Ñ DELETE в WITH ÑдалÑÐµÑ ÑказаннÑе ÑÑÑоки из products и возвÑаÑÐ°ÐµÑ Ð¸Ñ ÑодеÑжимое в пÑедложении RETURNING; а заÑем главнÑй запÑÐ¾Ñ ÑиÑÐ°ÐµÑ ÑÑо ÑодеÑжимое и вÑÑавлÑÐµÑ Ð² ÑаблиÑÑ products_log.
СледÑÐµÑ Ð·Ð°Ð¼ÐµÑиÑÑ, ÑÑо пÑедложение WITH в данном ÑлÑÑае пÑиÑоединÑеÑÑÑ Ðº опеÑаÑоÑÑ INSERT, а не к SELECT, Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½Ð¾Ð¼Ñ Ð² INSERT. ÐÑо Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾, Ñак как WITH Ð¼Ð¾Ð¶ÐµÑ ÑодеÑжаÑÑ Ð¾Ð¿ÐµÑаÑоÑÑ, изменÑÑÑие даннÑе, ÑолÑко на веÑÑ Ð½ÐµÐ¼ ÑÑовне запÑоÑа. Ðднако пÑи ÑÑом пÑименÑÑÑÑÑ Ð¾Ð±ÑÑнÑе пÑавила видимоÑÑи WITH, Ñак ÑÑо к ÑезÑлÑÑаÑÑ WITH можно обÑаÑиÑÑÑÑ Ð¸ из вложенного опеÑаÑоÑа SELECT.
ÐпеÑаÑоÑÑ, изменÑÑÑие даннÑе, в WITH обÑÑно дополнÑÑÑÑÑ Ð¿Ñедложением RETURNING, как показано в ÑÑом пÑимеÑе. Ðажно понимаÑÑ, ÑÑо вÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÑаблиÑа, коÑоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ бÑÐ´ÐµÑ Ð¸ÑполÑзоваÑÑ Ð² оÑÑалÑном запÑоÑе, ÑоздаÑÑÑÑ Ð¸Ð· ÑезÑлÑÑаÑа RETURNING, а не Ñелевой ÑаблиÑÑ Ð¾Ð¿ÐµÑаÑоÑа. ÐÑли опеÑаÑоÑ, изменÑÑÑий даннÑе в WITH, не дополнен пÑедложением RETURNING, вÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÑаблиÑа не ÑоздаÑÑÑÑ Ð¸ обÑаÑаÑÑÑÑ Ðº ней в оÑÑалÑном запÑоÑе нелÑзÑ. Ðднако Ñакой запÑÐ¾Ñ Ð²ÑÑ Ñавно бÑÐ´ÐµÑ Ð²Ñполнен. ÐапÑимеÑ, допÑÑÑим ÑледÑÑÑий не оÑÐµÐ½Ñ Ð¿ÑакÑиÑнÑй запÑоÑ:
WITH t AS (
DELETE FROM foo
)
DELETE FROM bar;Ðн ÑÐ´Ð°Ð»Ð¸Ñ Ð²Ñе ÑÑÑоки из ÑÐ°Ð±Ð»Ð¸Ñ foo и bar. ÐÑи ÑÑом ÑиÑло задейÑÑвованнÑÑ ÑÑÑок, коÑоÑое полÑÑÐ¸Ñ ÐºÐ»Ð¸ÐµÐ½Ñ, бÑÐ´ÐµÑ Ð¿Ð¾Ð´ÑÑиÑÑваÑÑÑÑ ÑолÑко по ÑÑÑокам, ÑдалÑннÑм из bar.
РекÑÑÑивнÑе ÑÑÑлки в опеÑаÑоÑÐ°Ñ , изменÑÑÑÐ¸Ñ Ð´Ð°Ð½Ð½Ñе, не допÑÑкаÑÑÑÑ. РнекоÑоÑÑÑ ÑлÑÑаÑÑ ÑÑо огÑаниÑение можно обойÑи, обÑаÑивÑиÑÑ Ðº конеÑÐ½Ð¾Ð¼Ñ ÑезÑлÑÑаÑÑ ÑекÑÑÑивного WITH, напÑÐ¸Ð¼ÐµÑ Ñак:
WITH RECURSIVE included_parts(sub_part, part) AS (
SELECT sub_part, part FROM parts WHERE part = 'our_product'
UNION ALL
SELECT p.sub_part, p.part
FROM included_parts pr, parts p
WHERE p.part = pr.sub_part
)
DELETE FROM parts
WHERE part IN (SELECT part FROM included_parts);ÐÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ ÑдалÑÐµÑ Ð²Ñе непоÑÑедÑÑвеннÑе и коÑвеннÑе ÑоÑÑавнÑе ÑаÑÑи пÑодÑкÑа.
ÐпеÑаÑоÑÑ, изменÑÑÑие даннÑе в WITH, вÑполнÑÑÑÑÑ ÑолÑко один Ñаз и вÑегда полноÑÑÑÑ, вне завиÑимоÑÑи Ð¾Ñ Ñого, пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ Ð»Ð¸ Ð¸Ñ ÑезÑлÑÑÐ°Ñ Ð¾Ñновной запÑоÑ. ÐамеÑÑÑе, ÑÑо ÑÑо оÑлиÑаеÑÑÑ Ð¾Ñ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ SELECT в WITH: как говоÑилоÑÑ Ð² пÑедÑдÑÑем Ñазделе, SELECT вÑполнÑеÑÑÑ ÑолÑко до ÑÐµÑ Ð¿Ð¾Ñ, пока его ÑезÑлÑÑаÑÑ Ð²Ð¾ÑÑÑÐµÐ±Ð¾Ð²Ð°Ð½Ñ Ð¾ÑновнÑм запÑоÑом.
ÐложеннÑе опеÑаÑоÑÑ Ð² WITH вÑполнÑÑÑÑÑ Ð¾Ð´Ð½Ð¾Ð²Ñеменно дÑÑг Ñ Ð´ÑÑгом и Ñ Ð¾ÑновнÑм запÑоÑом. Таким обÑазом, поÑÑдок, в коÑоÑом опеÑаÑоÑÑ Ð² WITH бÑдÑÑ ÑакÑиÑеÑки изменÑÑÑ Ð´Ð°Ð½Ð½Ñе, непÑедÑказÑем. ÐÑе ÑÑи опеÑаÑоÑÑ Ð²ÑполнÑÑÑÑÑ Ñ Ð¾Ð´Ð½Ð¸Ð¼ Ñнимком даннÑÑ (Ñм. ÐÐ»Ð°Ð²Ñ 13), Ñак ÑÑо они не могÑÑ "видеÑÑ", как каждÑй из Ð½Ð¸Ñ Ð¼ÐµÐ½ÑÐµÑ ÑелевÑе ÑаблиÑÑ. ÐÑо ÑменÑÑÐ°ÐµÑ ÑÑÑÐµÐºÑ Ð½ÐµÐ¿ÑедÑказÑемоÑÑи ÑакÑиÑеÑкого поÑÑдка Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑÑÑок и ознаÑаеÑ, ÑÑо RETURNING — единÑÑвеннÑй ваÑÐ¸Ð°Ð½Ñ Ð¿ÐµÑедаÑи изменений Ð¾Ñ Ð²Ð»Ð¾Ð¶ÐµÐ½Ð½ÑÑ Ð¾Ð¿ÐµÑаÑоÑов WITH оÑÐ½Ð¾Ð²Ð½Ð¾Ð¼Ñ Ð·Ð°Ð¿ÑоÑÑ. ÐапÑимеÑ, в данном ÑлÑÑае:
WITH t AS (
UPDATE products SET price = price * 1.05
RETURNING *
)
SELECT * FROM products;внеÑний опеÑаÑÐ¾Ñ SELECT вÑдаÑÑ ÑенÑ, коÑоÑÑе бÑли до дейÑÑÐ²Ð¸Ñ UPDATE, Ñогда как в запÑоÑе
WITH t AS (
UPDATE products SET price = price * 1.05
RETURNING *
)
SELECT * FROM t;внеÑний SELECT вÑдаÑÑ Ð¸Ð·Ð¼ÐµÐ½ÑннÑе даннÑе.
ÐеоднокÑаÑное изменение одной и Ñой же ÑÑÑоки в ÑÐ°Ð¼ÐºÐ°Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ опеÑаÑоÑа не поддеÑживаеÑÑÑ. ÐмеÑÑ Ð¼ÐµÑÑо бÑÐ´ÐµÑ ÑолÑко одно из неÑколÑÐºÐ¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ и надÑжно опÑеделиÑÑ, какое именно, ÑаÑÑо доволÑно Ñложно (а иногда и вовÑе невозможно). ÐÑо Ñак же каÑаеÑÑÑ ÑлÑÑаÑ, когда ÑÑÑока ÑдалÑеÑÑÑ Ð¸ изменÑеÑÑÑ Ð² Ñом же опеÑаÑоÑе: в ÑезÑлÑÑаÑе Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²Ñполнено ÑолÑко обновление. ÐоÑÑÐ¾Ð¼Ñ Ð² обÑем ÑлÑÑае ÑледÑÐµÑ Ð¸Ð·Ð±ÐµÐ³Ð°ÑÑ Ð¿Ð¾Ð´Ð¾Ð±Ð½Ð¾Ð³Ð¾ Ð½Ð°Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾Ð¿ÐµÑаÑий. Ð ÑаÑÑноÑÑи, избегайÑе подзапÑоÑов WITH, коÑоÑÑе могÑÑ Ð¿Ð¾Ð²Ð»Ð¸ÑÑÑ Ð½Ð° ÑÑÑоки, изменÑемÑе оÑновнÑм опеÑаÑоÑом или опеÑаÑоÑами, вложеннÑе в него. РезÑлÑÑÐ°Ñ Ð´ÐµÐ¹ÑÑÐ²Ð¸Ñ ÑÐ°ÐºÐ¸Ñ Ð·Ð°Ð¿ÑоÑов бÑÐ´ÐµÑ Ð½ÐµÐ¿ÑедÑказÑемÑм.
РнаÑÑоÑÑее вÑемÑ, Ð´Ð»Ñ Ð¾Ð¿ÐµÑаÑоÑа, изменÑÑÑего даннÑе в WITH, в каÑеÑÑве Ñелевой нелÑÐ·Ñ Ð¸ÑполÑзоваÑÑ ÑаблиÑÑ, Ð´Ð»Ñ ÐºÐ¾ÑоÑой опÑеделено ÑÑловное пÑавило или пÑавило ALSO или INSTEAD, еÑли оно ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· неÑколÑÐºÐ¸Ñ Ð¾Ð¿ÐµÑаÑоÑов.
| ÐÑед. | ÐаÑало | След. |
| СпиÑки VALUES | УÑÐ¾Ð²ÐµÐ½Ñ Ð²ÑÑе | Ð¢Ð¸Ð¿Ñ Ð´Ð°Ð½Ð½ÑÑ |