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_имейл | идентификатори ||-----------|-----------|-----|| (нула) | example@sqldat.com | 3 || example@sqldat.com | example@sqldat.com | 1,3 || example@sqldat.com | (нула) | 1 || example@sqldat.com | (нула) | 2 || (нула) | example@sqldat.com | 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 както и: