यह एक साधारण पुनरावर्ती सामान्य तालिका अभिव्यक्ति का एक उत्कृष्ट उपयोग है (WITH RECURSIVE
), PostgreSQL 8.4 और बाद के संस्करणों में उपलब्ध है।
यहां प्रदर्शित:http://sqlfiddle.com/#!12/78e15/9
नमूना डेटा को SQL के रूप में देखते हुए:
CREATE TABLE Table1
("ID1" text, "ID2" text)
;
INSERT INTO Table1
("ID1", "ID2")
VALUES
('vc1', 'vc2'),
('vc2', 'vc3'),
('vc3', 'vc4'),
('vc4', 'rc7')
;
आप लिख सकते हैं:
WITH RECURSIVE chain(from_id, to_id) AS (
SELECT NULL, 'vc2'
UNION
SELECT c.to_id, t."ID2"
FROM chain c
LEFT OUTER JOIN Table1 t ON (t."ID1" = to_id)
WHERE c.to_id IS NOT NULL
)
SELECT from_id FROM chain WHERE to_id IS NULL;
यह क्या करता है, प्रत्येक पंक्ति को chain
. में जोड़कर, श्रृंखला में चलना है तालिका से- और से-पॉइंटर्स के रूप में। जब यह एक पंक्ति का सामना करता है जिसके लिए 'से' संदर्भ मौजूद नहीं है तो यह उस पंक्ति के लिए एक शून्य 'से' संदर्भ जोड़ देगा। अगला पुनरावृत्ति ध्यान देगा कि 'से' संदर्भ शून्य है और शून्य पंक्तियों का उत्पादन करता है, जिससे पुनरावृत्ति समाप्त हो जाती है।
बाहरी क्वेरी तब उन पंक्तियों को चुनती है जिन्हें गैर-मौजूद to_id होने के कारण श्रृंखला के अंत के रूप में निर्धारित किया गया है।
रिकर्सिव सीटीई के आसपास अपना सिर पाने के लिए थोड़ा सा प्रयास करना पड़ता है। उन्हें समझने की मुख्य बातें हैं:
-
वे एक प्रारंभिक क्वेरी के आउटपुट के साथ शुरू करते हैं, जिसे वे बार-बार "रिकर्सिव पार्ट" के आउटपुट के साथ जोड़ते हैं (
UNION
के बाद की क्वेरी) याUNION ALL
) जब तक पुनरावर्ती भाग कोई पंक्तियाँ नहीं जोड़ता। यह पुनरावृत्ति को रोकता है। -
वे वास्तव में पुनरावर्ती नहीं हैं, अधिक पुनरावृत्त हैं, हालांकि वे उन चीजों के लिए अच्छे हैं जिनके लिए आप रिकर्सन का उपयोग कर सकते हैं।
तो आप मूल रूप से एक लूप में एक टेबल बना रहे हैं। आप पंक्तियों को हटा नहीं सकते हैं या उन्हें बदल नहीं सकते हैं, केवल नई जोड़ सकते हैं, इसलिए आपको आम तौर पर एक बाहरी क्वेरी की आवश्यकता होती है जो आपके इच्छित परिणाम पंक्तियों को प्राप्त करने के लिए परिणामों को फ़िल्टर करती है। आप अक्सर अतिरिक्त कॉलम जोड़ते हैं जिसमें मध्यवर्ती डेटा होता है जिसका उपयोग आप पुनरावृत्ति की स्थिति को ट्रैक करने, स्टॉप-शर्तों को नियंत्रित करने आदि के लिए करते हैं।
यह अनफ़िल्टर्ड परिणाम को देखने में मदद कर सकता है। अगर मैं अंतिम सारांश क्वेरी को एक साधारण SELECT * FROM chain
. से बदल दूं मैं जेनरेट की गई तालिका देख सकता हूं:
from_id | to_id
---------+-------
| vc2
vc2 | vc3
vc3 | vc4
vc4 | rc7
rc7 |
(5 rows)
पहली पंक्ति मैन्युअल रूप से जोड़ी गई प्रारंभिक बिंदु पंक्ति है, जहां आप निर्दिष्ट करते हैं कि आप क्या देखना चाहते हैं - इस मामले में वह vc2
था . प्रत्येक अनुवर्ती पंक्ति UNION
. द्वारा जोड़ी गई थी एड रिकर्सिव टर्म, जो एक LEFT OUTER JOIN
. करता है पिछले परिणाम पर और पंक्तियों का एक नया सेट लौटाता है जो पिछले to_id
. को जोड़ता है (अब from_id
. में कॉलम) अगले to_id
. पर . अगर LEFT OUTER JOIN
फिर to_id
. से मेल नहीं खाता शून्य हो जाएगा, जिससे अगला आह्वान अब पंक्तियों में वापस आ जाएगा और पुनरावृत्ति समाप्त हो जाएगी।
क्योंकि यह क्वेरी केवल अंतिम को जोड़ने का प्रयास नहीं करती है पंक्ति हर बार, यह वास्तव में प्रत्येक पुनरावृत्ति का एक अच्छा सा काम दोहरा रहा है। इससे बचने के लिए आपको गॉर्डन की तरह एक दृष्टिकोण का उपयोग करने की आवश्यकता होगी, लेकिन इसके अलावा पिछले गहराई क्षेत्र पर फ़िल्टर करें जब आप इनपुट तालिका को स्कैन करते हैं, तो आप केवल सबसे हाल की पंक्ति में शामिल हो जाते हैं। व्यवहार में यह आमतौर पर आवश्यक नहीं होता है, लेकिन यह बहुत बड़े डेटा सेट के लिए चिंता का विषय हो सकता है या जहां आप उपयुक्त अनुक्रमणिका नहीं बना सकते हैं।
सीटीई पर पोस्टग्रेएसक्यूएल दस्तावेज में और अधिक सीखा जा सकता है।