7.8. ÐапÑоÑÑ WITH (ÐбÑие ÑаблиÑнÑе вÑÑажениÑ) #
WITH пÑедоÑÑавлÑÐµÑ ÑпоÑоб запиÑÑваÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе опеÑаÑоÑÑ Ð´Ð»Ñ Ð¿ÑÐ¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² болÑÑиÑ
запÑоÑаÑ
. ÐÑи опеÑаÑоÑÑ, коÑоÑÑе Ñакже назÑваÑÑ Ð¾Ð±Ñими ÑаблиÑнÑми вÑÑажениÑми (Common Table Expressions, CTE), можно пÑедÑÑавиÑÑ ÐºÐ°Ðº опÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð²ÑеменнÑÑ
ÑаблиÑ, ÑÑÑеÑÑвÑÑÑиÑ
ÑолÑко Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ запÑоÑа. ÐополниÑелÑнÑм опеÑаÑоÑом в пÑедложении WITH Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ SELECT, INSERT, UPDATE, DELETE или MERGE, а Ñамо пÑедложение WITH пÑиÑоединÑеÑÑÑ Ðº оÑÐ½Ð¾Ð²Ð½Ð¾Ð¼Ñ Ð¾Ð¿ÐµÑаÑоÑÑ, коÑоÑÑм Ñакже Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ SELECT, INSERT, UPDATE, DELETE или MERGE.
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. ÐоказаннÑм вÑÑе ÑпоÑобом ÑÑо можно ÑделаÑÑ Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ пÑоÑе.
7.8.2. РекÑÑÑивнÑе запÑоÑÑ #
ÐеобÑзаÑелÑное Ñказание 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) оÑбÑаÑÑваÑÑÑÑ Ð´ÑблиÑÑÑÑиеÑÑ ÑÑÑоки и ÑÑÑоки, дÑблиÑÑÑÑие Ñанее полÑÑеннÑе. ÐÑе оÑÑавÑиеÑÑ ÑÑÑоки вклÑÑаÑÑÑÑ Ð² ÑезÑлÑÑÐ°Ñ ÑекÑÑÑивного запÑоÑа и Ñакже помеÑаÑÑÑÑ Ð²Ð¾ вÑеменнÑÑ Ð¿ÑомежÑÑоÑнÑÑ ÑаблиÑÑ.СодеÑжимое ÑабоÑей ÑаблиÑÑ Ð·Ð°Ð¼ÐµÐ½ÑеÑÑÑ ÑодеÑжимÑм пÑомежÑÑоÑной ÑаблиÑÑ, а заÑем пÑомежÑÑоÑÐ½Ð°Ñ ÑаблиÑа оÑиÑаеÑÑÑ.
ÐÑимеÑание
ХоÑÑ Ñказание 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 * pr.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_part7.8.2.1. ÐоÑÑдок поиÑка #
Ðогда пÑи вÑполнении ÑекÑÑÑивного запÑоÑа пÑоизводиÑÑÑ Ð¾Ð±Ñ Ð¾Ð´ деÑева, ÑезÑлÑÑаÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ полÑÑаÑÑ Ð² Ñазном поÑÑдке: «ÑнаÑала в глÑбинÑ» или «ÑнаÑала в ÑиÑинÑ». ÐÐ»Ñ ÑÑого можно в дополнение к дÑÑгим ÑÑолбÑам вÑÑиÑлиÑÑ ÑпоÑÑдоÑиваÑÑий ÑÑÐ¾Ð»Ð±ÐµÑ Ð¸ иÑполÑзоваÑÑ ÐµÐ³Ð¾ Ð´Ð»Ñ ÑоÑÑиÑовки ÑезÑлÑÑаÑов. ÐбÑаÑиÑе внимание, ÑÑо Ñакой ÑÑÐ¾Ð»Ð±ÐµÑ Ð½Ðµ опÑеделÑÐµÑ Ð¿Ð¾ÑÑдок Ð¾Ð±Ñ Ð¾Ð´Ð° ÑÑÑок запÑоÑом â ÑÑÐ¾Ñ Ð¿Ð¾ÑÑдок, как вÑегда, завиÑÐ¸Ñ Ð¾Ñ ÑеализаÑии SQL. УпоÑÑдоÑиваÑÑий ÑÑÐ¾Ð»Ð±ÐµÑ Ð»Ð¸ÑÑ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÐµÑ ÑдобнÑм обÑазом ÑпоÑÑдоÑиÑÑ Ð¿Ð¾Ð»ÑÑеннÑе ÑезÑлÑÑаÑÑ.
ЧÑÐ¾Ð±Ñ Ð¾ÑÑоÑÑиÑоваÑÑ ÑезÑлÑÑаÑÑ Ð² поÑÑдке «ÑнаÑала в глÑбинÑ», Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ ÑÑÑоки ÑезÑлÑÑаÑа вÑÑиÑлÑеÑÑÑ Ð¼Ð°ÑÑив Ñже пÑоÑмоÑÑеннÑÑ
ÑÑÑок. ÐапÑимеÑ, ÑаÑÑмоÑÑим ÑледÑÑÑий запÑоÑ, коÑоÑÑй вÑполнÑÐµÑ Ð¿Ð¾Ð¸Ñк в ÑаблиÑе tree по Ð¿Ð¾Ð»Ñ link:
WITH RECURSIVE search_tree(id, link, data) AS (
SELECT t.id, t.link, t.data
FROM tree t
UNION ALL
SELECT t.id, t.link, t.data
FROM tree t, search_tree st
WHERE t.id = st.link
)
SELECT * FROM search_tree;ЧÑÐ¾Ð±Ñ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð´Ð»Ñ ÑпоÑÑдоÑÐ¸Ð²Ð°Ð½Ð¸Ñ Â«ÑнаÑала в глÑбинÑ», Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе напиÑаÑÑ Ñак:
WITH RECURSIVE search_tree(id, link, data, path) AS ( SELECT t.id, t.link, t.data, ARRAY[t.id] FROM tree t UNION ALL SELECT t.id, t.link, t.data, path || t.id FROM tree t, search_tree st WHERE t.id = st.link ) SELECT * FROM search_tree ORDER BY path;
РобÑем ÑлÑÑае, когда Ð´Ð»Ñ Ð²ÑÑÐ²Ð»ÐµÐ½Ð¸Ñ ÑÑÑоки нÑжно иÑполÑзоваÑÑ Ð½ÐµÑколÑко полей, ÑледÑÐµÑ Ð¸ÑполÑзоваÑÑ Ð¼Ð°ÑÑив ÑÑÑок. ÐапÑимеÑ, еÑли нÑжно оÑÑледиÑÑ Ð¿Ð¾Ð»Ñ f1 и f2:
WITH RECURSIVE search_tree(id, link, data, path) AS ( SELECT t.id, t.link, t.data, ARRAY[ROW(t.f1, t.f2)] FROM tree t UNION ALL SELECT t.id, t.link, t.data, path || ROW(t.f1, t.f2) FROM tree t, search_tree st WHERE t.id = st.link ) SELECT * FROM search_tree ORDER BY path;
ÐодÑказка
ROW() можно опÑÑÑиÑÑ, когда нÑжно оÑÑлеживаÑÑ ÑолÑко одно поле (как обÑÑно и бÑваеÑ). ÐÑи ÑÑом бÑÐ´ÐµÑ Ð¸ÑполÑзоваÑÑÑÑ Ð½Ðµ маÑÑив даннÑÑ
ÑоÑÑавного Ñипа, а пÑоÑÑой маÑÑив, ÑÑо более ÑÑÑекÑивно.
ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ ÑезÑлÑÑаÑÑ, оÑÑоÑÑиÑованнÑе «ÑнаÑала в ÑиÑинÑ», можно добавиÑÑ ÑÑолбеÑ, оÑÑлеживаÑÑий глÑÐ±Ð¸Ð½Ñ Ð¿Ð¾Ð¸Ñка, напÑимеÑ:
WITH RECURSIVE search_tree(id, link, data, depth) AS ( SELECT t.id, t.link, t.data, 0 FROM tree t UNION ALL SELECT t.id, t.link, t.data, depth + 1 FROM tree t, search_tree st WHERE t.id = st.link ) SELECT * FROM search_tree ORDER BY depth;
ÐÐ»Ñ Ð¾Ð±ÐµÑпеÑÐµÐ½Ð¸Ñ ÑÑабилÑноÑÑи ÑоÑÑиÑовки добавÑÑе ÑÑолбÑÑ Ð´Ð°Ð½Ð½ÑÑ Ð² каÑеÑÑве ÑÑолбÑов вÑоÑиÑной ÑоÑÑиÑовки.
ÐодÑказка
ÐÑÐ¾Ñ Ð°Ð»Ð³Ð¾ÑиÑм ÑекÑÑÑивного вÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑоÑа вÑдаÑÑ Ð² ÑезÑлÑÑаÑе ÑзлÑ, ÑпоÑÑдоÑеннÑе «ÑнаÑала в ÑиÑинÑ». РвÑÑ Ð¶Ðµ ÑÑо завиÑÐ¸Ñ Ð¾Ñ ÑеализаÑии, поÑÑÐ¾Ð¼Ñ Ð¿Ð¾Ð»Ð°Ð³Ð°ÑÑÑÑ Ð½Ð° ÑÑо поведение не ÑледÑеÑ. ÐоÑÑдок ÑÑÑок внÑÑÑи каждого ÑÑовнÑ, конеÑно, не опÑеделÑн, поÑÑÐ¾Ð¼Ñ Ð² лÑбом ÑлÑÑае Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑÑебоваÑÑÑÑ Ñвное ÑпоÑÑдоÑивание.
ÐÐ»Ñ Ð¾Ð¿ÑÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÑÑолбÑа, коÑоÑÑй бÑÐ´ÐµÑ Ð²ÑÑиÑлÑÑÑÑÑ Ð´Ð»Ñ ÑпоÑÑдоÑÐ¸Ð²Ð°Ð½Ð¸Ñ Â«ÑнаÑала в глÑбинÑ» или «ÑнаÑала в ÑиÑинÑ», еÑÑÑ Ð²ÑÑÑоеннÑй ÑинÑакÑиÑ. ÐапÑимеÑ:
WITH RECURSIVE search_tree(id, link, data) AS (
SELECT t.id, t.link, t.data
FROM tree t
UNION ALL
SELECT t.id, t.link, t.data
FROM tree t, search_tree st
WHERE t.id = st.link
) SEARCH DEPTH FIRST BY id SET ordercol
SELECT * FROM search_tree ORDER BY ordercol;
WITH RECURSIVE search_tree(id, link, data) AS (
SELECT t.id, t.link, t.data
FROM tree t
UNION ALL
SELECT t.id, t.link, t.data
FROM tree t, search_tree st
WHERE t.id = st.link
) SEARCH BREADTH FIRST BY id SET ordercol
SELECT * FROM search_tree ORDER BY ordercol; ÐнÑÑÑи ÑÑÐ¾Ñ ÑинÑакÑÐ¸Ñ Ð¿ÑеобÑазÑеÑÑÑ Ð² ÑоÑмÑ, подобнÑе вÑÑепÑиведÑннÑм ÑоÑмам, ÑоÑÑавленнÑм вÑÑÑнÑÑ. РпÑедложении SEARCH ÑказÑваеÑÑÑ, какой Ñип поиÑка необÑ
одим â «ÑнаÑала в глÑбинÑ» или «ÑнаÑала в ÑиÑинÑ», ÑпиÑок оÑÑлеживаемÑÑ
Ð´Ð»Ñ ÑоÑÑиÑовки ÑÑолбÑов и Ð¸Ð¼Ñ ÑÑолбÑа, коÑоÑÑй бÑÐ´ÐµÑ ÑодеÑжаÑÑ Ð´Ð°Ð½Ð½Ñе, иÑполÑзÑемÑе Ð´Ð»Ñ ÑпоÑÑдоÑиваниÑ. ÐÑÐ¾Ñ ÑÑÐ¾Ð»Ð±ÐµÑ Ð±ÑÐ´ÐµÑ Ð½ÐµÑвно добавлен в ÑезÑлÑÑиÑÑÑÑие ÑÑÑоки в CTE.
7.8.2.2. ÐÑÑвление Ñиклов #
РабоÑÐ°Ñ Ñ ÑекÑÑÑивнÑми запÑоÑами, важно обеÑпеÑиÑÑ, ÑÑÐ¾Ð±Ñ ÑекÑÑÑÐ¸Ð²Ð½Ð°Ñ ÑаÑÑÑ Ð·Ð°Ð¿ÑоÑа в конÑе конÑов не вÑдала никакиÑ
коÑÑежей (ÑÑÑок), в пÑоÑивном ÑлÑÑае Ñикл бÑÐ´ÐµÑ Ð±ÐµÑконеÑнÑм. Ðногда Ð´Ð»Ñ ÑÑого доÑÑаÑоÑно пÑименÑÑÑ UNION вмеÑÑо UNION ALL, Ñак как пÑи ÑÑом бÑдÑÑ Ð¾ÑбÑаÑÑваÑÑÑÑ ÑÑÑоки, коÑоÑÑе Ñже еÑÑÑ Ð² ÑезÑлÑÑаÑе. Ðднако ÑаÑÑо в Ñикле вÑдаÑÑÑÑ ÑÑÑоки, не ÑовпадаÑÑие полноÑÑÑÑ Ñ Ð¿ÑедÑдÑÑими: в ÑакиÑ
ÑлÑÑаÑÑ
Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð¼ÐµÑÑ ÑмÑÑл пÑовеÑиÑÑ Ð¾Ð´Ð½Ð¾ или неÑколÑко полей, ÑÑÐ¾Ð±Ñ Ð¾Ð¿ÑеделиÑÑ, не бÑла ли ÑекÑÑÐ°Ñ ÑоÑка доÑÑигнÑÑа ÑанÑÑе. СÑандаÑÑнÑй ÑпоÑоб ÑеÑÐµÐ½Ð¸Ñ Ð¿Ð¾Ð´Ð¾Ð±Ð½ÑÑ
Ð·Ð°Ð´Ð°Ñ â вÑÑиÑлиÑÑ Ð¼Ð°ÑÑив Ñ Ñже обÑабоÑаннÑми знаÑениÑми. ÐапÑимеÑ, Ñнова ÑаÑÑмоÑÑиÑе ÑледÑÑÑий запÑоÑ, пÑоÑмаÑÑиваÑÑий ÑаблиÑÑ graph по Ð¿Ð¾Ð»Ñ link:
WITH RECURSIVE search_graph(id, link, data, depth) AS (
SELECT g.id, g.link, g.data, 0
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 не Ð¿Ð¾Ð·Ð²Ð¾Ð»Ð¸Ñ Ð¸Ð·Ð±ÐµÐ¶Ð°ÑÑ Ð·Ð°ÑикливаниÑ. ÐмеÑÑо ÑÑого Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ ÐºÐ°Ðº-Ñо опÑеделиÑÑ, ÑÑо Ñже доÑÑигали ÑекÑÑей ÑÑÑоки, пÑÐ¾Ð¹Ð´Ñ Ð½ÐµÐºÐ¾ÑоÑÑй пÑÑÑ. ÐÐ»Ñ ÑÑого, добавив два ÑÑолбÑа is_cycle и path, Ð¼Ñ Ð¿Ð¾Ð»ÑÑаем запÑоÑ, заÑиÑÑннÑй Ð¾Ñ Ð·Ð°ÑикливаниÑ:
WITH RECURSIVE search_graph(id, link, data, depth, is_cycle, path) AS ( SELECT g.id, g.link, g.data, 0, false, ARRAY[g.id] FROM graph g UNION ALL SELECT g.id, g.link, g.data, sg.depth + 1, g.id = ANY(path), path || g.id FROM graph g, search_graph sg WHERE g.id = sg.link AND NOT is_cycle ) SELECT * FROM search_graph;
Ðомимо пÑедоÑвÑаÑÐµÐ½Ð¸Ñ Ñиклов, знаÑÐµÐ½Ð¸Ñ Ð¼Ð°ÑÑива ÑаÑÑо бÑваÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ Ñами по Ñебе Ð´Ð»Ñ Ð¿ÑедÑÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Â«Ð¿ÑÑи», пÑиведÑего к опÑеделÑнной ÑÑÑоке.
РобÑем ÑлÑÑае, когда Ð´Ð»Ñ Ð²ÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñикла нÑжно пÑовеÑÑÑÑ Ð½ÐµÑколÑко полей, ÑледÑÐµÑ Ð¸ÑполÑзоваÑÑ Ð¼Ð°ÑÑив ÑÑÑок. ÐапÑимеÑ, еÑли нÑжно ÑÑавниÑÑ Ð¿Ð¾Ð»Ñ f1 и f2:
WITH RECURSIVE search_graph(id, link, data, depth, is_cycle, path) AS ( SELECT g.id, g.link, g.data, 0, false, ARRAY[ROW(g.f1, g.f2)] FROM graph g UNION ALL SELECT g.id, g.link, g.data, sg.depth + 1, ROW(g.f1, g.f2) = ANY(path), path || ROW(g.f1, g.f2) FROM graph g, search_graph sg WHERE g.id = sg.link AND NOT is_cycle ) SELECT * FROM search_graph;
ÐодÑказка
ЧаÑÑо Ð´Ð»Ñ Ð²ÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñикла доÑÑаÑоÑно одного полÑ, и Ñогда ROW() можно опÑÑÑиÑÑ. ÐÑи ÑÑом бÑÐ´ÐµÑ Ð¸ÑполÑзоваÑÑÑÑ Ð½Ðµ маÑÑив даннÑÑ
ÑоÑÑавного Ñипа, а пÑоÑÑой маÑÑив, ÑÑо более ÑÑÑекÑивно.
ÐÐ»Ñ ÑпÑоÑÐµÐ½Ð¸Ñ Ð²ÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñиклов еÑÑÑ Ð²ÑÑÑоеннÑй ÑинÑакÑиÑ. ÐапÑÐ¾Ñ Ð²ÑÑе можно запиÑаÑÑ Ñак:
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
) CYCLE id SET is_cycle USING path
SELECT * FROM search_graph; и внÑÑÑи он бÑÐ´ÐµÑ Ð¿ÑиведÑн к вÑÑеÑказанной ÑоÑме. РпÑедложении CYCLE ÑнаÑала ÑказÑваеÑÑÑ ÑпиÑок ÑÑолбÑов, оÑÑлеживаемÑÑ
Ð´Ð»Ñ Ð²ÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñикла, заÑем Ð¸Ð¼Ñ ÑÑолбÑа, показÑваÑÑего пÑизнак вÑÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñикла, и, наконеÑ, Ð¸Ð¼Ñ ÐµÑÑ Ð¾Ð´Ð½Ð¾Ð³Ð¾ ÑÑолбÑа, в коÑоÑом бÑÐ´ÐµÑ Ð¾ÑÑлеживаÑÑÑÑ Ð¿ÑÑÑ. СÑолбÑÑ, ÑказÑваÑÑие Ñикл и пÑÑÑ, бÑдÑÑ Ð½ÐµÑвно Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ Ð² ÑезÑлÑÑиÑÑÑÑие ÑÑÑоки в CTE.
ÐодÑказка
СÑÐ¾Ð»Ð±ÐµÑ Ñ Ñказанием пÑÑи Ñикла вÑÑиÑлÑеÑÑÑ Ñак же, как и ÑÑÐ¾Ð»Ð±ÐµÑ Ð´Ð»Ñ ÑпоÑÑдоÑÐ¸Ð²Ð°Ð½Ð¸Ñ ÑезÑлÑÑаÑов «ÑнаÑала в глÑбинÑ», ÑÑо показано в пÑедÑдÑÑем подÑазделе. ÐапÑÐ¾Ñ Ð¼Ð¾Ð¶ÐµÑ ÑодеÑжаÑÑ Ð¾Ð´Ð½Ð¾Ð²Ñеменно SEARCH и CYCLE, но в ÑÑом ÑлÑÑае Ð´Ð»Ñ ÑпоÑÑдоÑÐ¸Ð²Ð°Ð½Ð¸Ñ Â«ÑнаÑала в глÑбинÑ» бÑдÑÑ Ð¿ÑоизводиÑÑÑÑ Ð»Ð¸Ñние вÑÑиÑлениÑ, поÑÑÐ¾Ð¼Ñ ÑÑÑекÑивнее иÑполÑзоваÑÑ ÑолÑко CYCLE и ÑоÑÑиÑоваÑÑ ÑезÑлÑÑаÑÑ Ð¿Ð¾ ÑÑолбÑÑ Ð¿ÑÑи. Ðднако иÑполÑзование в запÑоÑе и SEARCH, и CYCLE опÑавдано, когда нÑжен поÑÑдок «ÑнаÑала в ÑиÑинÑ».
ÐÐ»Ñ ÑеÑÑиÑÐ¾Ð²Ð°Ð½Ð¸Ñ Ð·Ð°Ð¿ÑоÑов, коÑоÑÑе могÑÑ Ð·Ð°ÑикливаÑÑÑÑ, еÑÑÑ Ñ
оÑоÑий пÑиÑм â добавиÑÑ 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 полноÑÑÑÑ.
7.8.3. ÐаÑеÑиализаÑÐ¸Ñ Ð¾Ð±ÑÐ¸Ñ ÑаблиÑнÑÑ Ð²ÑÑажений #
ÐапÑоÑÑ WITH имеÑÑ Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾Ðµ ÑвойÑÑво â обÑÑно они вÑÑиÑлÑÑÑÑÑ ÑолÑко Ñаз Ð´Ð»Ñ Ð²Ñего ÑодиÑелÑÑкого запÑоÑа, даже еÑли ÑÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ Ð¸Ð»Ð¸ ÑоÑедние запÑоÑÑ WITH обÑаÑаÑÑÑÑ Ðº ним неоднокÑаÑно. Таким обÑазом, ÑложнÑе вÑÑиÑлениÑ, ÑезÑлÑÑаÑÑ ÐºÐ¾ÑоÑÑÑ
нÑÐ¶Ð½Ñ Ð² неÑколÑкиÑ
меÑÑаÑ
, можно вÑноÑиÑÑ Ð² запÑоÑÑ WITH в ÑелÑÑ
опÑимизаÑии. ÐÑоме Ñого, Ñакие запÑоÑÑ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÑÑ Ð¸Ð·Ð±ÐµÐ¶Ð°ÑÑ Ð½ÐµÐ¶ÐµÐ»Ð°ÑелÑнÑÑ
вÑÑиÑлений ÑÑнкÑий Ñ Ð¿Ð¾Ð±Ð¾ÑнÑми ÑÑÑекÑами. Ðднако еÑÑÑ Ð¸ обÑаÑÐ½Ð°Ñ ÑÑоÑона â опÑимизаÑÐ¾Ñ Ð½Ðµ Ð¼Ð¾Ð¶ÐµÑ ÑаÑпÑоÑÑÑаниÑÑ Ð¾Ð³ÑаниÑÐµÐ½Ð¸Ñ ÑодиÑелÑÑкого запÑоÑа на неоднокÑаÑно задейÑÑвÑемÑй запÑÐ¾Ñ WITH, Ñак как ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾Ð²Ð»Ð¸ÑÑÑ Ð½Ð° иÑполÑзование ÑезÑлÑÑаÑа WITH во вÑеÑ
меÑÑаÑ
, Ñогда как должно повлиÑÑÑ ÑолÑко в одном. ÐногокÑаÑно задейÑÑвÑемÑй запÑÐ¾Ñ WITH бÑÐ´ÐµÑ Ð²ÑполнÑÑÑÑÑ Ð±ÑквалÑно и возвÑаÑаÑÑ Ð²Ñе ÑÑÑоки, вклÑÑÐ°Ñ Ñе, ÑÑо поÑом Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑбÑоÑиÑÑ ÑодиÑелÑÑкий запÑоÑ. (Ðо как бÑло Ñказано вÑÑе, вÑÑиÑление Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑановиÑÑÑÑ ÑанÑÑе, еÑли в ÑÑÑлке на ÑÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ Ð·Ð°ÑÑебÑеÑÑÑ ÑолÑко огÑаниÑенное ÑиÑло ÑÑÑок.)
Ðднако еÑли запÑÐ¾Ñ WITH ÑвлÑеÑÑÑ Ð½ÐµÑекÑÑÑивнÑм и ÑвободнÑм Ð¾Ñ Ð¿Ð¾Ð±Ð¾ÑнÑÑ
ÑÑÑекÑов (Ñо еÑÑÑ ÑÑо SELECT, не вÑзÑваÑÑий изменÑивÑÑ
ÑÑнкÑий), он Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑвÑÑнÑÑ Ð² ÑодиÑелÑÑкий запÑоÑ, ÑÑо Ð¿Ð¾Ð·Ð²Ð¾Ð»Ð¸Ñ Ð¾Ð¿ÑимизиÑоваÑÑ ÑовмеÑÑно два ÑÑÐ¾Ð²Ð½Ñ Ð·Ð°Ð¿ÑоÑов. Ðо ÑмолÑÐ°Ð½Ð¸Ñ ÑÑо пÑоиÑÑ
одиÑ, ÑолÑко еÑли запÑÐ¾Ñ WITH задейÑÑвÑеÑÑÑ Ð² ÑодиÑелÑÑком запÑоÑе вÑего в одном меÑÑе, а не в неÑколÑкиÑ
. ÐÑо поведение можно пеÑеопÑеделиÑÑ, добавив Ñказание MATERIALIZED, ÑÑÐ¾Ð±Ñ Ð²ÑделиÑÑ Ð²ÑÑиÑление запÑоÑа WITH, или Ñказание NOT MATERIALIZED, ÑÑÐ¾Ð±Ñ Ð¿ÑинÑдиÑелÑно ÑвеÑнÑÑÑ ÐµÐ³Ð¾ в ÑодиÑелÑÑкий запÑоÑ. РпоÑледнем ÑлÑÑае Ð²Ð¾Ð·Ð½Ð¸ÐºÐ°ÐµÑ ÑиÑк многокÑаÑного вÑÑиÑÐ»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑоÑа WITH, но в иÑоге ÑÑо Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²Ñгодно, еÑли в каждом ÑлÑÑае иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ WITH из вÑего ÑезÑлÑÑаÑа запÑоÑа оÑÑаÑÑÑÑ ÑолÑко неболÑÑÐ°Ñ ÑаÑÑÑ.
ÐÑоÑÑой пÑÐ¸Ð¼ÐµÑ Ð´Ð»Ñ Ð´ÐµÐ¼Ð¾Ð½ÑÑÑаÑии ÑÑÐ¸Ñ Ð¿Ñавил:
WITH w AS (
SELECT * FROM big_table
)
SELECT * FROM w WHERE key = 123; ÐÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ WITH бÑÐ´ÐµÑ ÑвÑÑнÑÑ Ð² ÑодиÑелÑÑкий и бÑÐ´ÐµÑ Ð²Ñполнен Ñ Ñем же планом, ÑÑо и запÑоÑ:
SELECT * FROM big_table WHERE key = 123;
Ð ÑаÑÑноÑÑи, еÑли в ÑаблиÑе Ñоздан Ð¸Ð½Ð´ÐµÐºÑ Ð¿Ð¾ ÑÑолбÑÑ key, он Ð¼Ð¾Ð¶ÐµÑ Ð¸ÑполÑзоваÑÑÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ ÑÑÑок Ñ key = 123. РдÑÑгом ÑлÑÑае:
WITH w AS (
SELECT * FROM big_table
)
SELECT * FROM w AS w1 JOIN w AS w2 ON w1.key = w2.ref
WHERE w2.key = 123; запÑÐ¾Ñ WITH бÑÐ´ÐµÑ Ð¼Ð°ÑеÑиализован, Ñо еÑÑÑ ÑоздаÑÑÑÑ Ð²ÑÐµÐ¼ÐµÐ½Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ ÑаблиÑÑ big_table, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ñоединена Ñ Ñобой же, без иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ ÐºÐ°ÐºÐ¾Ð³Ð¾-либо индекÑа. ÐÑÐ¾Ñ Ð·Ð°Ð¿ÑÐ¾Ñ Ð±ÑÐ´ÐµÑ Ð²ÑполнÑÑÑÑÑ Ð³Ð¾Ñаздо ÑÑÑекÑивнее в Ñаком виде:
WITH w AS NOT MATERIALIZED (
SELECT * FROM big_table
)
SELECT * FROM w AS w1 JOIN w AS w2 ON w1.key = w2.ref
WHERE w2.key = 123; Ð ÑÑом ÑлÑÑае огÑаниÑÐµÐ½Ð¸Ñ ÑодиÑелÑÑкого запÑоÑа могÑÑ Ð¿ÑименÑÑÑÑÑ Ð½ÐµÐ¿Ð¾ÑÑедÑÑвенно пÑи ÑканиÑовании big_table.
ÐÑимеÑ, в коÑоÑом ваÑÐ¸Ð°Ð½Ñ NOT MATERIALIZED Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð½ÐµÐ¶ÐµÐ»Ð°ÑелÑнÑм:
WITH w AS (
SELECT key, very_expensive_function(val) as f FROM some_table
)
SELECT * FROM w AS w1 JOIN w AS w2 ON w1.f = w2.f; Рданном ÑлÑÑае благодаÑÑ Ð¼Ð°ÑеÑиализаÑии запÑоÑа WITH ÑеÑÑÑÑоÑÐ¼ÐºÐ°Ñ ÑÑнкÑÐ¸Ñ very_expensive_function вÑÑиÑлÑеÑÑÑ ÑолÑко один Ñаз Ð´Ð»Ñ ÑÑÑоки ÑаблиÑÑ, а не дваждÑ.
ÐÑимеÑÑ Ð²ÑÑе показÑваÑÑ ÑолÑко пÑедложение WITH Ñ SELECT, но Ñаким же обÑазом его можно иÑполÑзоваÑÑ Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ð¼Ð¸ INSERT, UPDATE, DELETE и MERGE. Ркаждом ÑлÑÑае он по ÑÑÑи ÑоздаÑÑ Ð²ÑеменнÑÑ ÑаблиÑÑ, к коÑоÑой можно обÑаÑиÑÑÑÑ Ð² оÑновной команде.
7.8.4. Ðзменение даннÑÑ
в WITH #
РпÑедложении WITH можно иÑполÑзоваÑÑ Ð¾Ð¿ÐµÑаÑоÑÑ, изменÑÑÑие даннÑе (INSERT, UPDATE, DELETE или MERGE). ÐÑо позволÑÐµÑ Ð²ÑполнÑÑÑ Ð² одном запÑоÑе ÑÑÐ°Ð·Ñ Ð½ÐµÑколÑко ÑазнÑÑ
опеÑаÑий. ÐапÑимеÑ:
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, еÑли оно ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· неÑколÑкиÑ
опеÑаÑоÑов.