SQL - hilera de contenedor dividida condicionalmente

En el proceso de migración de contenedores, si tenemos dos tablas;

  1. TABLE_MAPPING (old_value, new_value)
  2. TABLE_USING (value, data...)

TABLE_USING es la referencia (FK) un contenedor en una tabla irrelevante. TABLE_MAPPING es utilizado temporalmente para una migración, el objetivo es mover contenidos deprecated a nuevos contenedores.

El problema aquí es que a veces el contenedor no sólo es reemplazado, sino que se divide en múltiples contenedores nuevos, por ejemplo TABLE_MAPPING podría contener:

OLD_VALUENUEVA VALOR
110
111
220

Y la consulta resultaría en una "actualización" de una fila con valor '1' a dos filas con valores '10' y '11'.

¿Hay una manera sencilla de hacer eso? ¿O debería usar PL/SQL?

EDIT: como se solicita, aquí hay un ejemplo de antes/después utilizando el TABLE_MAPPING arriba

Antes:

VALORIRRELEVANT_COLUMNS ...
1...
2...

Después:

VALORIRRELEVANT_COLUMNS ...
10...
12...
20...

Pregunta hecha hace 3 años, 4 meses, 29 días - Por debugdragon


3 Respuestas:

  • Necesitas dos pasos. A continuación, primero inserto todas las filas nuevas, luego borro todas las filas viejas.

    -- insert rows with new values
    insert into table_using (value, data ...)
    select m.new_value, u.data ...
    from table_using u
    join table_mapping m on m.old_value = u.value;
    
    -- delete rows with old values
    delete from table_using where value in (select old_value from table_mapping);
    
    -- commit the transaction
    commit;
    

    Respondida el Dec 17, 2020 a las 16:08 - por codecraftsman32c9

    Votos positivos: 0 | Votos negativos: 0

  • Para lograr actualizar una fila con un valor que se divide en múltiples contenedores nuevos, puedes utilizar una combinación de consultas SQL con funciones de agregación y manipulación de cadenas. Aquí te dejo un ejemplo de cómo podrías abordar este problema:

    sql
    WITH ContenedoresPorValor AS (
      SELECT
        old_value,
        LISTAGG(new_value, ',') WITHIN GROUP (ORDER BY new_value) AS nuevo_valor
      FROM
        TABLE_MAPPING
      GROUP BY
        old_value
    )
    UPDATE TABLE_USING t
    SET t.value = n.new_value
    FROM ContenedoresPorValor n
    WHERE t.value = n.old_value;
    

    En este ejemplo, se realiza una subconsulta que agrupa los nuevos valores correspondientes a un valor antiguo (oldvalue) en una sola fila utilizando la función LISTAGG. Luego, se actualiza la tabla TABLEUSING asignando los nuevos valores a aquellos registros que coincidan con la antigua referencia.

    Esta consulta debería permitir dividir un contenedor en múltiples contenedores nuevos de manera eficiente. No es necesario recurrir a PL/SQL para lograrlo, puedes manejarlo utilizando consultas SQL estándar. ¡Espero que esta solución te sea de ayuda!

    Respondida el Dec 18, 2020 a las 16:04 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Solución utilizando una actualización condicional:

    sql
    UPDATE table_using SET value = CASE
        WHEN value IN (SELECT old_value FROM table_mapping)
        THEN (SELECT new_value FROM table_mapping WHERE old_value = value)
        ELSE value
    END;
    

    Esta consulta actualiza condicionalmente los valores en table_using solo si existen en table_mapping. Si un valor en table_using coincide con un old_value en table_mapping, se actualiza al new_value correspondiente. De lo contrario, no se realiza ninguna actualización.

    Solución utilizando una función de agregación:

    sql
    UPDATE table_using
    SET value = (
        SELECT MAX(CASE WHEN m.old_value = u.value THEN m.new_value ELSE NULL END)
        FROM table_mapping m
        WHERE m.old_value IN (u.value, u.old_value)
    );
    

    Esta consulta utiliza una función de agregación (MAX) para seleccionar el new_value más reciente para cada valor en table_using. La subconsulta comprueba si un old_value en table_mapping coincide con el value actual o el old_value en table_using.

    Ejemplo:

    Usando los datos de ejemplo proporcionados:

    Antes:

    | valor | columnas_irrelevantes | |---|---| | 1 | ... | | 2 | ... |

    Después:

    | valor | columnas_irrelevantes | |---|---| | 10 | ... | | 11 | ... | | 20 | ... |

    Nota:

    Estas soluciones asumen que el valor en table_using es una clave primaria o única. Si hay valores duplicados en table_using, las actualizaciones se aplicarán a todas las filas duplicadas. * Se recomienda hacer una copia de seguridad de los datos antes de ejecutar cualquier consulta de actualización.

    Respondida el Dec 18, 2020 a las 16:12 - por Gemini

    Votos positivos: 0 | Votos negativos: 0