demo1:db<>fiddle , demo2:db<>fiddle
WITH combined AS (
SELECT
a.email as a_email,
b.email as b_email,
array_remove(ARRAY[a.id, b.id], NULL) as ids
FROM
a
FULL OUTER JOIN b ON (a.email = b.email)
), clustered AS (
SELECT DISTINCT
ids
FROM (
SELECT DISTINCT ON (unnest_ids)
*,
unnest(ids) as unnest_ids
FROM combined
ORDER BY unnest_ids, array_length(ids, 1) DESC
) s
)
SELECT DISTINCT
new_id,
unnest(array_cat) as email
FROM (
SELECT
array_cat(
array_agg(a_email) FILTER (WHERE a_email IS NOT NULL),
array_agg(b_email) FILTER (WHERE b_email IS NOT NULL)
),
row_number() OVER () as new_id
FROM combined co
JOIN clustered cl
ON co.ids <@ cl.ids
GROUP BY cl.ids
) s
चरण दर चरण स्पष्टीकरण:
स्पष्टीकरण के लिए मैं यह डेटासेट लूंगा। यह आपकी तुलना में थोड़ा अधिक जटिल है। यह मेरे कदमों को बेहतर तरीके से समझा सकता है। आपके छोटे सेट में कुछ समस्याएं नहीं होती हैं। वर्णों के बारे में ईमेल पतों के लिए चर के रूप में सोचें।
तालिका A:
| id | email |
|----|-------|
| 1 | a |
| 1 | b |
| 2 | c |
| 5 | e |
टेबल बी
| id | email |
|----|-------|
| 3 | a |
| 3 | d |
| 4 | e |
| 4 | f |
| 3 | b |
सीटीई combined
:
स्पर्श बिंदु प्राप्त करने के लिए एक ही ईमेल पते पर दोनों तालिकाओं में शामिल हों। एक ही आईडी की आईडी को एक सरणी में जोड़ा जाएगा:
| a_email | b_email | ids |
|-----------|-----------|-----|
| (null) | [email protected] | 3 |
| [email protected] | [email protected] | 1,3 |
| [email protected] | (null) | 1 |
| [email protected] | (null) | 2 |
| (null) | [email protected] | 4 |
सीटीई clustered
(नामों के लिए खेद है...):
लक्ष्य सभी तत्वों को केवल एक सरणी में प्राप्त करना है। combined
. में आप देख सकते हैं, उदाहरण के लिए वर्तमान में 4
. तत्व के साथ अधिक सरणियाँ हैं :{5,4}
और {4}
।
पहले पंक्तियों को उनके ids
. की लंबाई के अनुसार क्रमित करना सरणियाँ क्योंकि DISTINCT
बाद में सबसे लंबी सरणी लेनी चाहिए (क्योंकि स्पर्श बिंदु को पकड़े हुए {5,4}
{4}
. के बजाय )।
फिर unnest
ids
फ़िल्टरिंग के लिए आधार प्राप्त करने के लिए सरणी। यह इस पर समाप्त होता है:
| a_email | b_email | ids | unnest_ids |
|---------|---------|-----|------------|
| b | b | 1,3 | 1 |
| a | a | 1,3 | 1 |
| c | (null) | 2 | 2 |
| b | b | 1,3 | 3 |
| a | a | 1,3 | 3 |
| (null) | d | 3 | 3 |
| e | e | 5,4 | 4 |
| (null) | f | 4 | 4 |
| e | e | 5,4 | 5 |
DISTINCT ON
. के साथ फ़िल्टर करने के बाद
| a_email | b_email | ids | unnest_ids |
|---------|---------|-----|------------|
| b | b | 1,3 | 1 |
| c | (null) | 2 | 2 |
| b | b | 1,3 | 3 |
| e | e | 5,4 | 4 |
| e | e | 5,4 | 5 |
हम केवल ids
. में रुचि रखते हैं उत्पन्न अद्वितीय आईडी क्लस्टर के साथ कॉलम। इसलिए हमें उन सभी की केवल एक बार आवश्यकता है। यह आखिरी का काम है DISTINCT
. तो CTE clustered
परिणाम
| ids |
|-----|
| 2 |
| 1,3 |
| 5,4 |
अब हम जानते हैं कि कौन सी आईडी संयुक्त हैं और उन्हें अपना डेटा साझा करना चाहिए। अब हम क्लस्टर किए गए ids
. में शामिल हो गए हैं मूल तालिकाओं के विपरीत। चूंकि हमने इसे CTE combined
. में किया है हम इस हिस्से का पुन:उपयोग कर सकते हैं (यही कारण है कि इसे एक सीटीई में आउटसोर्स किया जाता है:हमें अब इस चरण में दोनों तालिकाओं के एक और जुड़ाव की आवश्यकता नहीं है)। जॉइन ऑपरेटर <@
कहते हैं:अगर combined
. के "टच पॉइंट" सरणी में शामिल हों clustered
. के आईडी क्लस्टर का एक उपसमूह है . यह इसमें उत्पन्न होता है:
| a_email | b_email | ids | ids |
|---------|---------|-----|-----|
| c | (null) | 2 | 2 |
| a | a | 1,3 | 1,3 |
| b | b | 1,3 | 1,3 |
| (null) | d | 3 | 1,3 |
| e | e | 5,4 | 5,4 |
| (null) | f | 4 | 5,4 |
अब हम क्लस्टर आईडी (सबसे दाहिने कॉलम) का उपयोग करके ईमेल पतों को समूहबद्ध करने में सक्षम हैं।
array_agg
एक कॉलम के मेल को एकत्रित करता है, array_cat
दोनों स्तंभों के ईमेल सरणियों को एक बड़े ईमेल सरणी में संयोजित करता है।
चूंकि ऐसे कॉलम हैं जहां ईमेल NULL
है हम FILTER (WHERE...)
. के साथ क्लस्टर करने से पहले इन मानों को फ़िल्टर कर सकते हैं खंड।
अब तक का परिणाम:
| array_cat |
|-----------|
| c |
| a,b,a,b,d |
| e,e,f |
अब हम सभी ईमेल पतों को एक ही आईडी के लिए समूहित करते हैं। हमें नई यूनिक आईडी बनानी होगी। यही है विंडो फ़ंक्शन
row_number
के लिए है। यह केवल तालिका में एक पंक्ति गणना जोड़ता है:
| array_cat | new_id |
|-----------|--------|
| c | 1 |
| a,b,a,b,d | 2 |
| e,e,f | 3 |
अंतिम चरण है unnest
प्रति ईमेल पता एक पंक्ति प्राप्त करने के लिए सरणी। चूंकि सरणी में अभी भी कुछ डुप्लीकेट हैं, इसलिए हम उन्हें इस चरण में DISTINCT
के साथ समाप्त कर सकते हैं साथ ही:
| new_id | email |
|--------|-------|
| 1 | c |
| 2 | a |
| 2 | b |
| 2 | d |
| 3 | e |
| 3 | f |