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; Ðо в данном ÑлÑÑае ÑÑого не пÑоиÑÑ
одиÑ, Ñак как в Postgres Pro запÑÐ¾Ñ 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 (Ñм. Раздел 6.4), как показано в ÑÑом пÑимеÑе. Ðажно понимаÑÑ, ÑÑо вÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÑаблиÑа, коÑоÑÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ бÑÐ´ÐµÑ Ð¸ÑполÑзоваÑÑ Ð² оÑÑалÑном запÑоÑе, ÑоздаÑÑÑÑ Ð¸Ð· ÑезÑлÑÑаÑа 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, еÑли оно ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· неÑколÑкиÑ
опеÑаÑоÑов.