demo1:db<>fiddle , demo2:db<>fiddle
С комбиниран AS ( ИЗБЕРЕТЕ a.email като a_email, b.email като b_email, array_remove(ARRAY[a.id, b.id], NULL) като ids FROM a FULL OUTER JOIN b ON (a. имейл =b.email)), клъстериран AS ( ИЗБЕРЕТЕ РАЗЛИЧНИ ids FROM ( ИЗБЕРЕТЕ РАЗЛИЧНИ ON (unnest_ids) *, unnest(ids) като unnest_ids FROM комбиниран ORDER BY unnest_ids, array_length(ids, 1) DESC ) s)SELECT DISTINCT new_id, unnest(array_cat) като emailFROM ( 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 комбиниран co JOIN клъстерен cl ON co.ids <@ cl.ids GROUP BY cl.ids) s
Обяснение стъпка по стъпка:
За обяснение ще взема този набор от данни. Това е малко по-сложно от вашето. Може да илюстрира стъпките ми по-добре. Някои проблеми не възникват във вашия по-малък комплект. Мислете за знаците като променливи за имейл адреси.
Таблица A:
<предварителен код>| ID | имейл ||----|-------|| 1 | а || 1 | b || 2 | c || 5 | e |Таблица Б
<предварителен код>| ID | имейл ||----|-------|| 3 | а || 3 | d || 4 | д || 4 | е || 3 | b |
CTE комбиниран
:
СЪЕДИНЯВАНЕ на двете таблици на едни и същи имейл адреси, за да получите допирна точка. Идентификаторите на същите идентификатори ще бъдат свързани в един масив:
<предварителен код>| a_имейл | b_имейл | идентификатори ||-----------|-----------|-----|| (нула) | [email protected] | 3 || [email protected] | [email protected] | 1,3 || [email protected] | (нула) | 1 || [email protected] | (нула) | 2 || (нула) | [email protected] | 4 |
CTE групиран
(съжалявам за имената...):
Целта е да получите всички елементи точно в един масив. В комбинирано
можете да видите, например в момента има повече масиви с елемента 4
:{5,4}
и {4}
.
Първо подреждане на редовете по дължината на техните id
масиви, защото DISTINCT
по-късно трябва да вземе най-дългия масив (тъй като държи точката на допир {5,4}
вместо {4}
).
След това unnest
id
масиви, за да получите основа за филтриране. Това завършва на:
След филтриране с DISTINCT ON
Интересуваме се само от id
колона с генерираните уникални id клъстери. Така че имаме нужда от всички само веднъж. Това е работата на последния DISTINCT
. Така че CTE групиран
води до
Сега знаем кои идентификатори са комбинирани и трябва да споделяме техните данни. Сега се присъединяваме към групираните id
срещу таблиците за произход. Тъй като направихме това в CTE combined
можем да използваме повторно тази част (това е причината, поради която между другото е изнесена в един CTE:вече не се нуждаем от друго обединяване на двете таблици в тази стъпка). Операторът JOIN <@
казва:ПРИСЪЕДИНЯВАНЕ, ако масивът "точка на допир" от комбиниран
е подгрупа на id клъстера на clustered
. Това води до:
Сега можем да групираме имейл адресите, като използваме групираните идентификатори (най-дясната колона).
array_agg
агрегира имейлите от една колона, array_cat
обединява имейл масивите от двете колони в един голям имейл масив.
Тъй като има колони, където имейлът е NULL
можем да филтрираме тези стойности преди клъстериране с FILTER (WHERE...)
клауза.
Резултат до момента:
<предварителен код>| array_cat ||-----------|| c || a,b,a,b,d || e,e,f |
Сега групираме всички имейл адреси за един единствен идентификатор. Трябва да генерираме нови уникални идентификатори. Това е, което прозоречната функция
номер_на_ред
е за. Той просто добавя брой редове към таблицата:
Последната стъпка е unnest
масива, за да получите ред за имейл адрес. Тъй като в масива все още има някои дубликати, можем да ги елиминираме в тази стъпка с DISTINCT
както и: