sql >> Base de Datos >  >> RDS >> PostgreSQL

PostgreSQL:inserte filas según la selección de otra tabla y actualice un FK en esa tabla con las filas recién insertadas

Hay varias formas de resolver el problema.

1. agregar temporalmente una columna

Como mencionaron otros, la forma sencilla es agregar temporalmente una columna reminder_id al dateset . Rellénelo con IDs originales de reminder mesa. Úselo para unirse a reminder con el dateset mesa. Suelta la columna temporal.

2. cuando el inicio es único

Si los valores de start la columna es única, es posible hacerlo sin una columna adicional uniéndose a reminder tabla con el dateset tabla en el start columna.

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. cuando el inicio no es único

Es posible hacerlo sin columna temporal incluso en este caso. La idea principal es la siguiente. Echemos un vistazo a este ejemplo:

Tenemos dos filas en reminder con el mismo start valor e ID 3 y 7:

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

Después de insertarlos en el dateset , se generarán nuevos ID, por ejemplo, 1 y 2:

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

Realmente no importa cómo unimos estas dos filas. El resultado final podría ser

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

o

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

Ambas variantes son correctas. Lo que nos lleva a la siguiente solución.

Simplemente inserte todas las filas primero.

INSERT INTO dateset (start)
SELECT start FROM reminder;

Haga coincidir o únase a dos tablas en start columna sabiendo que no es única. "Hazlo" único agregando ROW_NUMBER y unidos por dos columnas. Es posible acortar la consulta, pero deletreé cada paso explícitamente:

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
;

Espero que quede claro en el código lo que hace, especialmente cuando lo comparas con la versión más simple sin ROW_NUMBER . Obviamente, la solución compleja funcionará incluso si start es único, pero no es tan eficiente como una solución simple.

Esta solución asume que dateset está vacío antes de este proceso.