Как объединить строки в таблице и обновить таблицу соединений на postgres - PullRequest
0 голосов
/ 05 июня 2019

Рассмотрим 2 таблицы (table A и table B) с отношением «многие ко многим», каждая из которых содержит первичный ключ и другие атрибуты.Чтобы отобразить это отношение, существует третья объединенная таблица (table C), содержащая внешние ключи для каждой таблицы отношения (fk_tableA | fk_tableB).

Table B содержит повторяющиеся строки (кроме pk), поэтомуЯ хочу объединить их в одну запись с любым уникальным первичным ключом, например, так:

table B                   table B (after merging duplicates)
1 | Henry | 100.0         1 | Henry | 100.0
2 | Jessi | 97.0          2 | Jessi | 97.0
3 | Henry | 100.0         4 | Erica | 11.2
4 | Erica | 11.2

При объединении этих записей могут существовать внешние ключи table C (объединенная таблица), указывающие на первичныйключи table B, которые больше не существуют.Моя цель - отредактировать их так, чтобы они указывали на объединенную запись:

Перед объединением:

tableA         table B               table C

id | att1      id | att1 | att2      fk_A | fk_b
-----------   -------------------    ------------
 1 | ab123     1 | Henry | 100.0        1 | 1 
 2 | adawd     2 | Jessi | 97.0         2 | 3  
 3 | da3wf     3 | Henry | 100.0    
               4 | Erica | 11.2

При table C ссылки на 2 записи из table B (1 и 3), которыеслучается, дублированные строки.Моя цель - объединить их в одну запись (в table B) и обновить внешний ключ в table C:

После объединения:

tableA         table B               table C

id | att1      id | att1 | att2      fk_A | fk_b
-----------   -------------------    ------------
 1 | ab123     1 | Henry | 100.0        1 | 1 
 2 | adawd     2 | Jessi | 97.0         2 | 1
 3 | da3wf     4 | Erica | 11.2   

- Note that id=3 was merged/deleted from table B and the same id
  was updated on table C to point to the merged record's id.

Так что мой вопрос в основном как обновить таблицу соединений при объединении записей таблицы? В настоящее время я использую Postgres и работаю с миллионами данных.

1 Ответ

1 голос
/ 05 июня 2019
-- \i tmp.sql

CREATE TABLE persons
        ( id integer primary key
        , name text
        , weight decimal(4,1)
        );

INSERT INTO persons(id,name,weight)VALUES
 (1 ,'Henry', 100.0)
 ,(2 ,'Jessi', 97.0)
 ,(3 ,'Henry', 100.0)
 ,(4 ,'Erica', 11.)
        ;

CREATE TABLE junctiontab
        ( fk_A integer NOT NULL
        , p_id integer REFERENCES persons(id)
        , PRIMARY KEY (fk_A,p_id)
         );

INSERT INTO junctiontab(fk_A, p_id)VALUES (1 , 1 ),(2 , 3  );

        -- find the ids of affected persons.
        -- [for simplicity: put them in a temp table]
CREATE TEMP table xlat AS
SELECT * FROM(
        SELECt id AS wrong_id
                ,min(id) OVER (PARTITION BY name ORDER BY id) AS good_id
        FROM persons p
        ) x
WHERE good_id <> wrong_id
        ;

        --show it
SELECT *FROM xlat;

UPDATE junctiontab j
SET p_id = x.good_id
FROM xlat x
WHERE j.p_id = x.wrong_id
        -- The good junction-entry *could* already exist...
AND NOT EXISTS (
        SELECT *FROM junctiontab nx
        WHERE nx.fk_A= j.fk_A
        AND nx.p_id= x.good_id
        )
        ;

DELETE FROM junctiontab d
        -- if the good junction-entry already existed, we can delete the wrong one now.
WHERE EXISTS (
        SELECT *FROM junctiontab g
        JOIN xlat x ON g.p_id= x.good_id
                   AND d.p_id = x.wrong_id
        WHERE g.fk_A= d.fk_A
        )
        ;

        --show it
SELECT *FROM junctiontab
        ;

        -- Delete thewrongperson-records
DELETE FROM persons p
WHERE EXISTS (
        SELECT *FROM xlat x
        WHERE p.id = x.wrong_id
        );

        --show it
SELECT * FROM persons p;

Результат:


DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 4
CREATE TABLE
INSERT 0 2
SELECT 1
 wrong_id | good_id 
----------+---------
        3 |       1
(1 row)

UPDATE 1
DELETE 0
 fk_a | p_id 
------+------
    1 |    1
    2 |    1
(2 rows)

DELETE 1
 id | name  | weight 
----+-------+--------
  1 | Henry |  100.0
  2 | Jessi |   97.0
  4 | Erica |   11.0
(3 rows)
...