uso transponer pasar filas fila convertir columnas columna cambiar sql oracle merge ora-38104

pasar - transponer columnas en filas sql



ORA-38104: las columnas a las que se hace referencia en la cláusula ON no se pueden actualizar (4)

"Las inserciones y actualizaciones condicionales ahora son posibles mediante el uso de una cláusula WHERE en estas declaraciones". http://www.oracle-base.com/articles/10g/merge-enhancements-10g.php

Tengo una tabla simple con un indicador de eliminación (los registros deben actualizarse en esta columna en lugar de eliminarse):

create table PSEUDODELETETABLE ( ID NUMBER(8) not null, -- PKEY NAME VARCHAR2(50) not null, ISDELETED NUMBER(1) default 0 not null )

Al insertar nuevos registros, debo verificar si ya existe un registro que coincida con la clave principal pero que tenga el valor ISDELETED = 1. En ese caso, debo cambiar el valor de ISDELETED a 0 y actualizar las otras columnas. Por lo tanto estoy usando la siguiente declaración de fusión:

merge into ET.PSEUDODELETETABLE TARGET using (select 1 as ID, ''Horst'' as NAME from sys.dual) SOURCE on (TARGET.ISDELETED = 1 and SOURCE.ID = TARGET.ID) when matched then update set ISDELETED = 0, NAME = SOURCE.NAME when not matched then insert values (SOURCE.ID, SOURCE.NAME, 0);

En Sql-Server funciona muy bien, pero Oracle dice:

ORA-38104: Columns referenced in the ON Clause cannot be updated: TARGET.ISDELETED

Si hay un registro coincidente con IDELETED = 0, quiero que la violación de la clave principal sea una excepción, es por eso que no puedo mover "TARGET.ISDELETED = 1" de la cláusula on a la instrucción update.


Contrariamente a la respuesta aceptada, en realidad hay una manera de lograrlo: mueva el bit ofensivo de la cláusula ON y colóquela en la cláusula WHERE de la instrucción de actualización:

merge into ET.PSEUDODELETETABLE TARGET using (select 1 as ID, ''Horst'' as NAME from sys.dual) SOURCE on (SOURCE.ID = TARGET.ID) when matched then update set ISDELETED = 0, NAME = SOURCE.NAME where TARGET.ISDELETED = 1 -- Magic! when not matched then insert values (SOURCE.ID, SOURCE.NAME, 0);


Sospecho que estás mejor en este caso con un algoritmo de disparar y mirar.

Dependiendo de lo que esperas que sea el caso más frecuente, ya sea:

  • Actualice, y si no se actualizan filas, inserte; o
  • Insertar, y si hay una violación clave, actualizar.

También debemos considerar el siguiente escenario,

Si hay un registro coincidente con IDELETED = 0 , quiero que la violación de la clave principal sea una excepción, es por eso que no puedo mover "TARGET.ISDELETED = 1" de la cláusula on a la instrucción update.

Así que la solución exacta es la siguiente,

begin update ET.PSEUDODELETETABLE set ISDELETED = 0, NAME = ''Horst'' where ISDELETED = 1 and ID = 1; if (sql%rowcount = 0) then insert into ET.PSEUDODELETETABLE values (1, ''Horst'', 0); end if; end;