PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Postgres:Обединете акаунти в една самоличност чрез общ имейл адрес

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 масиви, за да получите основа за филтриране. Това завършва на:

<предварителен код>| a_имейл | b_имейл | идентификатори | unnest_ids ||---------|---------|-----|-------------|| б | б | 1,3 | 1 || a | a | 1,3 | 1 || c | (нула) | 2 | 2 || б | б | 1,3 | 3 || a | a | 1,3 | 3 || (нула) | d | 3 | 3 || д | д | 5,4 | 4 || (нула) | е | 4 | 4 || д | д | 5,4 | 5 |

След филтриране с DISTINCT ON

<предварителен код>| a_имейл | b_имейл | идентификатори | unnest_ids ||---------|---------|-----|-------------|| б | б | 1,3 | 1 || c | (нула) | 2 | 2 || б | б | 1,3 | 3 || д | д | 5,4 | 4 || д | д | 5,4 | 5 |

Интересуваме се само от id колона с генерираните уникални id клъстери. Така че имаме нужда от всички само веднъж. Това е работата на последния DISTINCT . Така че CTE групиран води до

<предварителен код>| идентификатори ||-----|| 2 || 1,3 || 5,4 |

Сега знаем кои идентификатори са комбинирани и трябва да споделяме техните данни. Сега се присъединяваме към групираните id срещу таблиците за произход. Тъй като направихме това в CTE combined можем да използваме повторно тази част (това е причината, поради която между другото е изнесена в един CTE:вече не се нуждаем от друго обединяване на двете таблици в тази стъпка). Операторът JOIN <@ казва:ПРИСЪЕДИНЯВАНЕ, ако масивът "точка на допир" от комбиниран е подгрупа на id клъстера на clustered . Това води до:

<предварителен код>| a_имейл | b_имейл | идентификатори | идентификатори ||---------|---------|-----|-----|| c | (нула) | 2 | 2 || a | a | 1,3 | 1,3 || б | б | 1,3 | 1,3 || (нула) | d | 3 | 1,3 || д | д | 5,4 | 5,4 || (нула) | е | 4 | 5,4 |

Сега можем да групираме имейл адресите, като използваме групираните идентификатори (най-дясната колона).

array_agg агрегира имейлите от една колона, array_cat обединява имейл масивите от двете колони в един голям имейл масив.

Тъй като има колони, където имейлът е NULL можем да филтрираме тези стойности преди клъстериране с FILTER (WHERE...) клауза.

Резултат до момента:

<предварителен код>| array_cat ||-----------|| c || a,b,a,b,d || e,e,f |

Сега групираме всички имейл адреси за един единствен идентификатор. Трябва да генерираме нови уникални идентификатори. Това е, което прозоречната функция номер_на_ред е за. Той просто добавя брой редове към таблицата:

<предварителен код>| array_cat | нов_ид ||-----------|--------|| c | 1 || a,b,a,b,d | 2 || e,e,f | 3 |

Последната стъпка е unnest масива, за да получите ред за имейл адрес. Тъй като в масива все още има някои дубликати, можем да ги елиминираме в тази стъпка с DISTINCT както и:

<предварителен код>| нов_ид | имейл ||--------|-------|| 1 | c || 2 | а || 2 | b || 2 | d || 3 | д || 3 | f |

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как работи Trunc() в PostgreSQL

  2. postgresql тригер на tvector колона получава ГРЕШКА:колоната не съществува

  3. Как да генерирам Postgresql Dump от Docker контейнер?

  4. Python/Flask:Как да разберете колко време потребителят прекарва на страница? (Приложение за въвеждане на данни/дневник на времето)

  5. Sqlalchemy не работи с пагинация