282 votos

Oracle SQL: Update con datos de otra tabla

Tabla uno:

id    name    desc
-----------------------
1     a       abc
2     b       def
3     c       adf

Table dos:

id    name    desc
-----------------------
1     x       123
2     y       345

En Oracle SQL, ¿cómo puedo ejecutar un Update de Sql que puede actualizar la Tabla 1 con el nombre de la Tabla 2 y desc usando el mismo id? Así que el resultado final que obtendría es

Tabla uno:

id    name    desc
-----------------------
1     x       123
2     y       345
3     c       adf

La pregunta se toma de Consulta de actualización de sql con datos de otra tabla pero específicamente para Oracle SQL.

2 votos

0 votos

Tienes que volver a tu otra pregunta, desechar esa respuesta e indicar específicamente que necesitas la sintaxis PLSQL de Oracle.

3 votos

@p.campbell, Esa no es mi pregunta...

569voto

Justin Cave Puntos 114578

Esto se llama una actualización correlativa

UPDATE table1 t1
   SET (name, desc) = (SELECT t2.name, t2.desc
                         FROM table2 t2
                        WHERE t1.id = t2.id)
 WHERE EXISTS (
    SELECT 1
      FROM table2 t2
     WHERE t1.id = t2.id )

Asumiendo que la unión da como resultado una vista clave preservada, también podría

UPDATE (SELECT t1.id, 
               t1.name name1,
               t1.desc desc1,
               t2.name name2,
               t2.desc desc2
          FROM table1 t1,
               table2 t2
         WHERE t1.id = t2.id)
   SET name1 = name2,
       desc1 = desc2

8 votos

En su primer ejemplo de código: ¿Es necesaria la cláusula externa WHERE para obtener resultados correctos? ¿O la utiliza sólo para acelerar la consulta?

51 votos

@totoro - En el primer ejemplo, el WHERE EXISTS impide que se actualice una fila en t1 si no hay ninguna fila que coincida en t2 . Sin ella, cada fila de t1 se actualizará y los valores se ajustarán a NULL si no hay ninguna fila que coincida en t2 . Por lo general, eso no es lo que se quiere que ocurra, así que el WHERE EXISTS es generalmente necesario.

5 votos

Cabe añadir que el SELECT ... FROM t2 debe resultan en una fila única. Esto significa que tiene que seleccionar todos los campos que componen una clave única - una clave primaria no única no es suficiente. Sin la unicidad, se reduce a algo como El bucle de @PaulKarr -- y si no hay una correlación única, entonces se puede actualizar más de una fila de destino por cada fila de origen.

20voto

Yahia Puntos 49011

pruebe

UPDATE Table1 T1 SET
T1.name = (SELECT T2.name FROM Table2 T2 WHERE T2.id = T1.id),
T1.desc = (SELECT T2.desc FROM Table2 T2 WHERE T2.id = T1.id)
WHERE T1.id IN (SELECT T2.id FROM Table2 T2 WHERE T2.id = T1.id);

5 votos

El inconveniente de esto es que la sentencia SELECT se repite 3 veces. En ejemplos complejos esto puede ser un problema.

11voto

Pau Karr Puntos 46
Update table set column = (select...)

nunca funcionó para mí ya que set sólo espera un valor - Error SQL: ORA-01427: la subconsulta de una sola fila devuelve más de una fila.

aquí está la solución:

BEGIN
For i in (select id, name, desc from table1) 
LOOP
Update table2 set name = i.name, desc = i.desc where id = i.id;
END LOOP;
END;

Así es exactamente como lo ejecutas en la hoja de trabajo de SQLDeveloper. Dicen que es lento pero es la única solución que me ha funcionado en este caso.

0 votos

¿alguien puede explicar por qué esto merece un -2 en reputación? LOL.

13 votos

No he bajado la tarifa, pero no es una buena solución. En primer lugar: si la subselección devolvía múltiples valores, entonces el bucle for estará sobrescribiendo el nombre en la tabla2 múltiples veces para algunos/todos los registros (no es limpio). En segundo lugar: no hay cláusula de orden por lo que esto ocurrirá de manera impredecible (es decir, el último valor en los datos desordenados gana). Tercero: Será mucho más lento. Asumiendo que el resultado del bucle for era el deseado, la subselección original podría haber sido reescrita de alguna manera controlada para devolver sólo 1 valor por cada registro... la manera más sencilla sería (select min(name)...)

0 votos

Esto era exactamente lo que necesitaba. Gracias (+1)

8voto

ant Puntos 65

Aquí parece haber una respuesta aún mejor con la cláusula "in" que permite múltiples claves para la unión:

update fp_active set STATE='E', 
   LAST_DATE_MAJ = sysdate where (client,code) in (select (client,code) from fp_detail
  where valid = 1) ...

El ejemplo completo está aquí: http://forums.devshed.com/oracle-development-96/how-to-update-from-two-tables-195893.html

El problema está en tener las columnas que quieres usar como la clave entre paréntesis en la cláusula where antes de 'in' y tener la declaración selectora con los mismos nombres de columna entre paréntesis. donde (columna1, columna2) en ( seleccione (columna1, columna2) de la mesa donde "el juego que quiero" );

0 votos

El enlace ha caducado. ( 404 )

-2voto

Jim P Puntos 209

Si tu tabla t1 y su copia de seguridad t2 tienen muchas columnas, aquí tienes una forma compacta de hacerlo.

Además, mi problema relacionado fue que sólo algunas de las columnas fueron modificadas y muchas filas no tenían ediciones en estas columnas, así que quise dejarlas en paz - básicamente restaurar un subconjunto de columnas a partir de una copia de seguridad de toda la tabla. Si quieres restaurar todas las filas, salta la cláusula "dónde".

Por supuesto que la forma más simple sería borrar e insertar como seleccionar, pero en mi caso necesitaba una solución con sólo actualizaciones.

El truco es que cuando seleccionas * de un par de tablas con nombres de columnas duplicados, la segunda se llamará _1. Así que esto es lo que se me ocurrió:

  update (
    select * from t1 join t2 on t2.id = t1.id
    where id in (
      select id from (
        select id, col1, col2, ... from t2
        minus select id, col1, col2, ... from t1
      )
    )
  ) set col1=col1_1, col2=col2_1, ...

0 votos

Esto no me funciona en Oracle 11g. Puede crear un ejemplo de trabajo de este método?

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X