2012-12-08 3 views
6

मैं पेड़ प्रजनन परियोजना के लिए एक रैखिक वंश सूची बनाना चाहता हूं। माता-पिता पुरुष/महिला है कि संबंधित नहीं किया जाना चाहिए (कोई आंतरिक प्रजनन) पर नज़र रखने और इन वंशावली कल्पना करने के लिए जोड़े, इसलिए महत्व रहे हैं ...पोस्टग्रेएसक्यूएल 2 अभिभावक/बाल तालिकाओं के माध्यम से रिकर्सिव

नीचे परीक्षण तालिकाओं/Postgresql 9.1 का उपयोग कर डेटा है:

DROP TABLE if exists family CASCADE; 
DROP TABLE if exists plant CASCADE; 

CREATE TABLE family ( 
    id serial, 
    family_key VARCHAR(20) UNIQUE, 
    female_plant_id INTEGER NOT NULL DEFAULT 1, 
    male_plant_id INTEGER NOT NULL DEFAULT 1, 
    filial_n INTEGER NOT NULL DEFAULT -1, -- eg 0,1,2... Which would represent None, F1, F2... 
    CONSTRAINT family_pk PRIMARY KEY (id) 
); 

CREATE TABLE plant ( 
    id serial, 
    plant_key VARCHAR(20) UNIQUE, 
    id_family INTEGER NOT NULL, 
    CONSTRAINT plant_pk PRIMARY KEY (id), 
    CONSTRAINT plant_id_family_fk FOREIGN KEY(id_family) REFERENCES family(id) -- temp may need to remove constraint... 
); 

-- FAMILY Table DATA: 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (1,'NA',1,1,1); -- Default place holder record 
-- Root level Alba families 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (2,'family1AA',2,3,1); 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (3,'family2AA',4,5,1); 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (4,'family3AA',6,7,1); 
-- F2 Hybrid Families 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (5,'family4AE',8,11,0); 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (6,'family5AG',9,12,0); 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (7,'family6AT',10,13,0); 
-- F3 Double Hybrid family: 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (9,'family7AEAG',14,15,0); 
-- F3 Tri-hybrid backcross family: 
insert into family (id, family_key, female_plant_id, male_plant_id, filial_n) VALUES (10,'family8AEAGAT',17,16,0); 

-- PLANT Table DATA: 
-- Root level Alba Parents: 
insert into plant (id, plant_key, id_family) VALUES (1,'NA',1);  -- Default place holder record 
insert into plant (id, plant_key, id_family) VALUES (2,'female1A',1); 
insert into plant (id, plant_key, id_family) VALUES (3,'male1A',1); 
insert into plant (id, plant_key, id_family) VALUES (4,'female2A',1); 
insert into plant (id, plant_key, id_family) VALUES (5,'male2A',1); 
insert into plant (id, plant_key, id_family) VALUES (6,'female3A',1); 
insert into plant (id, plant_key, id_family) VALUES (7,'male3A',1); 
-- Female Alba progeny: 
insert into plant (id, plant_key, id_family) VALUES (8,'female4A',2); 
insert into plant (id, plant_key, id_family) VALUES (9,'female5A',3); 
insert into plant (id, plant_key, id_family) VALUES (10,'female6A',4); 
-- Male Aspen Root level parents: 
insert into plant (id, plant_key, id_family) VALUES (11,'male1E',1); 
insert into plant (id, plant_key, id_family) VALUES (12,'male1G',1); 
insert into plant (id, plant_key, id_family) VALUES (13,'female1T',1); 
-- F1 Hybrid progeny: 
insert into plant (id, plant_key, id_family) VALUES (14,'female1AE',5); 
insert into plant (id, plant_key, id_family) VALUES (15,'male1AG',6); 
insert into plant (id, plant_key, id_family) VALUES (16,'male1AT',7); 
-- Hybrid progeny 
insert into plant (id, plant_key, id_family) VALUES (17,'female1AEAG',9); 
-- Tri-hybrid backcross progeny: 
insert into plant (id, plant_key, id_family) VALUES (18,'female1AEAGAT',10); 
insert into plant (id, plant_key, id_family) VALUES (19,'female2AEAGAT',10); 

नीचे पुनरावर्ती पूछताछ कि मैं Postgres WITH Queries प्रलेखन से प्राप्त होता है:

WITH RECURSIVE search_tree(
     family_key 
    , female_plant 
    , male_plant 
    , depth 
    , path 
    , cycle 
) AS (
    SELECT 
      f.family_key 
     , pf.plant_key 
     , pm.plant_key 
     , 1 
     , ARRAY[ROW(pf.plant_key, pm.plant_key)] 
     , false 
    FROM 
      family f 
     , plant pf 
     , plant pm 
    WHERE 
     f.female_plant_id = pf.id 
     AND f.male_plant_id = pm.id 
     AND f.filial_n = 1 -- Include only F1 families (root level) 
     AND f.id <> 1  -- omit the default first family record 

    UNION ALL 

    SELECT 
      f.family_key 
     , pf.plant_key 
     , pm.plant_key 
     , st.depth + 1 
     , path || ROW(pf.plant_key, pm.plant_key) 
     , ROW(pf.plant_key, pm.plant_key) = ANY(path) 
    FROM 
      family f 
     , plant pf 
     , plant pm 
     , search_tree st 
    WHERE 
     f.female_plant_id = pf.id 
     AND f.male_plant_id = pm.id 
     AND f.family_key = st.family_key 
     AND pf.plant_key = st.female_plant 
     AND pm.plant_key = st.male_plant 
     AND f.filial_n <> 1 -- Include only non-F1 families (non-root levels) 
     AND NOT cycle 
) 
SELECT * FROM search_tree; 

नीचे वांछित आउटपुट है:

F1 family1AA=(female1A x male1A) > F2 family4AE=(female4A x male1E) > F3 family7AEAG=(female1AE x male1AG) > F4 family8AEAGAT=(female1AEAG x male1AT) 
F1 family2AA=(female2A x male2A) > F2 family5AG=(female5A x male1G) > F3 family7AEAG=(female1AE x male1AG) > F4 family8AEAGAT=(female1AEAG x male1AT) 
F1 family3AA=(female3A x male3A) > F2 family6AT=(female6A x female1T) > F3 family8AEAGAT=(female1AEAG x male1AT) 

उपर्युक्त रिकर्सिव क्वेरी उपयुक्त एफ 1 माता-पिता के साथ 3 पंक्तियां प्रदर्शित करती है लेकिन पथ डाउनस्ट्रीम परिवार/माता-पिता को प्रदर्शित नहीं करता है। मैं ऊपर सूचीबद्ध वांछित आउटपुट के समान रिकर्सिव आउटपुट बनाने में मदद की सराहना करता हूं।

+0

अच्छा सवाल है, बहुत अच्छी तरह से डाल दिया। बहुत पूरा मैं इस पर काम कर रहा हूं ... – wildplasser

+0

मुझे यकीन नहीं है कि मैं समझता हूं कि पदानुक्रम कैसे परिभाषित किया गया है। मुझे उदाहरण सारणी में अभिभावक/बाल संबंध नहीं मिल रहा है। क्या आप इस बारे में कुछ समझ सकते हैं कि अभिभावक (या बच्चा) कैसे पाया जाता है? –

+0

क्या यह संभव है कि 'plant.id = 11' वाली पंक्ति' '_'' family_id' के रूप में होनी चाहिए? –

उत्तर

4

मैं मैं क्या समझ लिया है करने के लिए क्वेरी ढाल लिया है, जरूरी क्या आवश्यकता है :-)

क्वेरी के लिए नहीं तीन दिए गए f.id != 1 AND f.filial_n = 1 द्वारा परिभाषित परिवारों पर शुरू होता है और रिकर्सिवली उपलब्ध बच्चों फैलता है।

किस शर्त पर केवल पिछले तीन मैचों का चयन किया जाना चाहिए मेरी समझ से परे है। शायद प्रत्येक शुरुआती परिवार के लिए एन्केस्टर्स की सबसे लंबी श्रृंखला?

WITH RECURSIVE expanded_family AS (
    SELECT 
     f.id, 
     f.family_key, 
     pf.id   pd_id, 
     pf.plant_key pf_key, 
     pf.id_family pf_family, 
     pm.id   pm_id, 
     pm.plant_key pm_key, 
     pm.id_family pm_family, 
     f.filial_n 
    FROM family f 
     JOIN plant pf ON f.female_plant_id = pf.id 
     JOIN plant pm ON f.male_plant_id = pm.id 
), 
search_tree AS (
    SELECT 
     f.*, 
     1 depth, 
     ARRAY[f.family_key::text] path 
    FROM expanded_family f 
    WHERE 
     f.id != 1 
     AND f.filial_n = 1 
    UNION ALL 
    SELECT 
     f.*, 
     depth + 1, 
     path || f.family_key::text 
    FROM search_tree st 
     JOIN expanded_family f 
      ON f.pf_family = st.id 
      OR f.pm_family = st.id 
    WHERE 
     f.id <> 1 
) 
SELECT 
    family_key, 
    depth, 
    path 
FROM search_tree; 

परिणाम है:

family_key | depth |      path      
---------------+-------+------------------------------------------------- 
family1AA  |  1 | {family1AA} 
family2AA  |  1 | {family2AA} 
family3AA  |  1 | {family3AA} 
family4AE  |  2 | {family1AA,family4AE} 
family5AG  |  2 | {family2AA,family5AG} 
family6AT  |  2 | {family3AA,family6AT} 
family7AEAG |  3 | {family1AA,family4AE,family7AEAG} 
family7AEAG |  3 | {family2AA,family5AG,family7AEAG} 
family8AEAGAT |  3 | {family3AA,family6AT,family8AEAGAT} 
family8AEAGAT |  4 | {family1AA,family4AE,family7AEAG,family8AEAGAT} 
family8AEAGAT |  4 | {family2AA,family5AG,family7AEAG,family8AEAGAT} 

तकनीकी सामान:

  • मैं cycle सामान निकाल दी हैं क्योंकि स्वच्छ डेटा के लिए यह आवश्यक (IMHO) नहीं होना चाहिए।

  • expanded_family कुछ अजीब प्रदर्शन समस्या होने पर रेखांकित किया जा सकता है, लेकिन अब यह रिकर्सिव क्वेरी को अधिक पठनीय बनाता है।

संपादित

क्वेरी इन पंक्तियों जहां, प्रत्येक "रूट" परिवार (अर्थात लोगों जिसके लिए क्वेरी शुरू कर दिया) के लिए, सबसे लंबे समय तक पथ मौजूद फ़िल्टर कर सकते हैं की एक मामूली संशोधन।

मैं search_tree में केवल बदली हुई हिस्सा दिखाने के लिए, तो आप पिछले भाग से सिर नकल करने के लिए है:

-- ... 
search_tree AS 
(
    SELECT 
     f.*, 
     f.id   family_root, -- remember where the row came from. 
     1 depth, 
     ARRAY[f.family_key::text] path 
    FROM expanded_family f 
    WHERE 
     f.id != 1 
     AND f.filial_n = 1 
    UNION ALL 
    SELECT 
     f.*, 
     st.family_root, -- propagate the anchestor 
     depth + 1, 
     path || f.family_key::text 
    FROM search_tree st 
     JOIN expanded_family f 
      ON f.pf_family = st.id 
      OR f.pm_family = st.id 
    WHERE 
     f.id <> 1 
) 
SELECT 
    family_key, 
    path 
FROM 
(
    SELECT 
     rank() over (partition by family_root order by depth desc), 
     family_root, 
     family_key, 
     depth, 
     path 
    FROM search_tree 
) AS ranked 
WHERE rank = 1; 

परिणाम है:

family_key |      path      
---------------+------------------------------------------------- 
family8AEAGAT | {family1AA,family4AE,family7AEAG,family8AEAGAT} 
family8AEAGAT | {family2AA,family5AG,family7AEAG,family8AEAGAT} 
family8AEAGAT | {family3AA,family6AT,family8AEAGAT} 
(3 rows) 

EDIT2

टिप्पणियों के आधार पर मैंने पथ के pretty_print संस्करण को जोड़ा:

WITH RECURSIVE expanded_family AS (
    SELECT 
     f.id, 
     pf.id_family pf_family, 
     pm.id_family pm_family, 
     f.filial_n, 
     f.family_key || '=(' || pf.plant_key || ' x ' || pm.plant_key || ')' pretty_print 
    FROM family f 
     JOIN plant pf ON f.female_plant_id = pf.id 
     JOIN plant pm ON f.male_plant_id = pm.id 
), 
search_tree AS 
(
    SELECT 
     f.id, 
     f.id   family_root, 
     1 depth, 
     'F1 ' || f.pretty_print path 
    FROM expanded_family f 
    WHERE 
     f.id != 1 
     AND f.filial_n = 1 
    UNION ALL 
    SELECT 
     f.id, 
     st.family_root, 
     st.depth + 1, 
     st.path || ' -> F' || st.depth+1 || ' ' || f.pretty_print 
    FROM search_tree st 
     JOIN expanded_family f 
      ON f.pf_family = st.id 
      OR f.pm_family = st.id 
    WHERE 
     f.id <> 1 
) 
SELECT 
    path 
FROM 
(
    SELECT 
     rank() over (partition by family_root order by depth desc), 
     path 
    FROM search_tree 
) AS ranked 
WHERE rank = 1; 

परिणाम

path                   
---------------------------------------------------------------------------------------------------------------------------------------------------------- 
F1 family1AA=(female1A x male1A) -> F2 family4AE=(female4A x male1E) -> F3 family7AEAG=(female1AE x male1AG) -> F4 family8AEAGAT=(female1AEAG x male1AT) 
F1 family2AA=(female2A x male2A) -> F2 family5AG=(female5A x male1G) -> F3 family7AEAG=(female1AE x male1AG) -> F4 family8AEAGAT=(female1AEAG x male1AT) 
F1 family3AA=(female3A x male3A) -> F2 family6AT=(female6A x female1T) -> F3 family8AEAGAT=(female1AEAG x male1AT) 
(3 rows) 
+0

बहुत बढ़िया - मुझे इसे यहां से लेने में सक्षम होना चाहिए! मैं डुप्लिकेट पूर्वजों को हटाने और अभिभावक/बाल स्वरूपण को जोड़ने के लिए पीएल/पीजीएसक्यूएल का उपयोग कर सकता हूं। आपकी सहायताके लिए धन्यवाद! आपने बेहतर पेड़ पैदा करने में मदद की है !!! – user1888167

+0

@ user1888167: pl/pgsql की आवश्यकता नहीं है। आप तीन स्थानों में उपयुक्त फ़िल्टर जोड़ सकते हैं: गैर-रिकर्सिव भाग का 'WHERE' (जहां' f.id' और 'f.filial_id' पहले से ही चेक किए गए हैं), रिकर्सिव 'WHERE' और आप एक फ़िल्टर भी जोड़ सकते हैं "बाहरी" का चयन करें। इस तरह की चीजों के लिए "बाहरी" 'चयन 'सामान्य जगह है। फ़िल्टरिंग करने के लिए आप वर्तमान आउटपुट शो की तुलना में अधिक जानकारी का उपयोग कर सकते हैं।
मुझे नहीं पता था कि आप कौन से मानदंडों को लागू करना चाहते हैं। –

+0

सबसे वांछनीय मानदंड केवल "पूर्ण परिवार के प्लेथ" को प्रदर्शित करना होगा, जो आपके आउटपुट की आखिरी तीन पंक्तियां होगी। तो हाँ, प्रत्येक शुरुआती परिवार के लिए यह एन्केस्टर्स की सबसे लंबी अनूठी श्रृंखला होगी? क्या यह संभव है? – user1888167

संबंधित मुद्दे