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

PostgreSQL - вмъкване на редове въз основа на избор от друга таблица и актуализиране на FK в тази таблица с нововмъкнатите редове

Има няколко начина за решаване на проблема.

1. временно добавяне на колоната

Както други споменаха, директният начин е временно да добавите колона reminder_id към dateset . Попълнете го с оригинални IDs от reminder маса. Използвайте го, за да се присъедините към reminder с dateset маса. Пуснете временната колона.

2. когато стартът е уникален

Ако стойностите на start колоната е уникална, възможно е да го направите без допълнителна колона, като се присъедините към reminder таблица с dateset таблица в start колона.

INSERT INTO dateset (start)
SELECT start FROM reminder;

WITH
CTE_Joined
AS
(
    SELECT
        reminder.id AS reminder_id
        ,reminder.dateset_id AS old_dateset_id
        ,dateset.id AS new_dateset_id
    FROM
        reminder
        INNER JOIN dateset ON dateset.start = reminder.start
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

3. когато стартът не е уникален

Възможно е дори в този случай да се направи без временна колона. Основната идея е следната. Нека да разгледаме този пример:

Имаме два реда в reminder със същия start стойност и идентификатори 3 и 7:

reminder
id    start         dateset_id
3     2015-01-01    NULL
7     2015-01-01    NULL

След като ги вмъкнем в dateset , ще бъдат генерирани нови идентификатори, например 1 и 2:

dateset
id    start
1     2015-01-01
2     2015-01-01

Всъщност няма значение как свързваме тези два реда. Крайният резултат може да бъде

reminder
id    start         dateset_id
3     2015-01-01    1
7     2015-01-01    2

или

reminder
id    start         dateset_id
3     2015-01-01    2
7     2015-01-01    1

И двата варианта са верни. Което ни води до следното решение.

Просто първо вмъкнете всички редове.

INSERT INTO dateset (start)
SELECT start FROM reminder;

Сравнете/съединете две таблици при start колона, знаейки, че не е уникална. „Направете го“ уникален, като добавите ROW_NUMBER и съединяване с две колони. Възможно е заявката да бъде по-кратка, но изрично описах всяка стъпка:

WITH
CTE_reminder_rn
AS
(
    SELECT
        id
        ,start
        ,dateset_id
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM reminder
)
,CTE_dateset_rn
AS
(
    SELECT
        id
        ,start
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM dateset
)
,CTE_Joined
AS
(
    SELECT
        CTE_reminder_rn.id AS reminder_id
        ,CTE_reminder_rn.dateset_id AS old_dateset_id
        ,CTE_dateset_rn.id AS new_dateset_id
    FROM
        CTE_reminder_rn
        INNER JOIN CTE_dateset_rn ON 
            CTE_dateset_rn.start = CTE_reminder_rn.start AND
            CTE_dateset_rn.rn = CTE_reminder_rn.rn
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

Надявам се, че от кода става ясно какво прави, особено когато го сравнявате с по-простата версия без ROW_NUMBER . Очевидно сложното решение ще работи дори ако start е уникален, но не е толкова ефективен, колкото просто решение.

Това решение предполага, че dateset е празен преди този процес.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да излезете от помощната програма на командния ред PostgreSQL:psql

  2. pg_dump не е намерен в rails

  3. Свържете pyodbc към Postgres

  4. fe_sendauth:грешка без предоставена парола след настройка на PostgreSQL база данни в Cloud9 IDE

  5. Разлика между поточна репликация и логическа репликация