UPSERT en la tabla con el nombre dynamic de la tabla

Cualquier método mejor para UPSERT en una tabla, siempre que:

  • Data upsert a ~ 1 fila / segundo
  • El nombre de la tabla es DINÁMICO, generado con el parámetro ObjectID que se le pasó

EL SIGUIENTE PROCEDIMIENTO LANZA: "ORA-00942: tabla o vista no existe"

CREATE OR REPLACE PROCEDURE PROCEDURE "SPINSERTDATA" ( pObjectID IN RAW, pDateTime IN TIMESTAMP, pValue IN BINARY_DOUBLE, ) AS BEGIN Declare vQueryInsert VARCHAR2(1000); vQueryUpdate VARCHAR2(1000); vTableName VARCHAR2(30); Begin vTableName := FGETTABLENAME(POBJECTID => pObjectID); vQueryUpdate := 'UPDATE ' || vTableName || ' SET "VALUE" = :1'; vQueryInsert := 'INSERT INTO ' || vTableName || ' ("DTTIME", "VALUE") VALUES (:1, :2)'; EXECUTE IMMEDIATE vQueryInsert USING pDateTime, pValue; EXCEPTION WHEN DUP_VAL_ON_INDEX THEN EXECUTE IMMEDIATE vQueryUpdate USING pValue; End; END "SPINSERTDATA"; 
  • Aparentemente MERGE no funciona ya que TableName no puede ser dynamic ???
  • Soy un novato, mi tercer mes de encoding, lloré a través de STACKOVERFLOW & Googled durante 3 días, probando todo tipo de soluciones divertidas y desesperadas … Incluso un enlace muy relevante si encuentras uno sería sinceramente apreciado.

MERGE funciona perfectamente bien con SQL dynamic nativo (EJECUTAR INMEDIATO):

 create table so_test(pk number not null primary key, value varchar2(20)); insert into so_test(pk, value) values(1, 'one'); declare l_SQL varchar2(4000); l_tablename varchar2(4000) default 'so_test'; begin l_SQL := 'merge into ' || l_tablename || ' target' || ' using (select 1 pk, ''eins'' value from dual union all select 2 pk, ''zwei'' value from dual) source on (target.pk = source.pk) when matched then update set target.value = source.value when not matched then insert values(source.pk, source.value) '; dbms_output.put_line(l_sql); execute immediate l_SQL; end; 

¿Podría publicar el post de error que aparece al usar MERGE?

Debe considerar escribir esto para usar SQL estático en lugar de pasar el nombre de la tabla en time de ejecución. ¿Hay alguna razón válida por la que no sabes a qué table te unirías hasta el time de ejecución?

En cuanto a la debugging del problema …

¿Cómo se define la function FGETTABLENAME en tu código? Esto es lo que se me ocurrió que imita ese escenario. Yo sugeriría el uso de declaraciones% type (en lugar de RAW para types de numbers) y eliminar las comillas dobles del procedimiento Names.

  create or replace function FGETTABLENAME( POBJECTID in user_objects.object_id%type ) return user_objects.object_name%type as v_object_name user_objects.object_name%type; begin select object_name into v_object_name from all_objects where object_id = pobjectid; return v_object_name; end; / SQL> select object_id, object_name from user_objects; OBJECT_ID OBJECT_NAME ---------- -------------------------------------------- 52641 TFIVE 52644 SPINSERTDATA 52643 PROCEDURE 52645 FGETTABLENAME 52554 GET_SAL_EMP 52559 T1 SQL> select FGETTABLENAME(52641) from dual; FGETTABLENAME(52641) -------------------------------------------- TFIVE 

Puede agregar instrucciones DBMS_OUTPUT.PUT_LINE a su código después de

 vTableName := FGETTABLENAME(POBJECTID => pObjectID); and vQueryUpdate := 'UPDATE ' || vTableName || ' SET "VALUE" = :1'; vQueryInsert := 'INSERT INTO ' || vTableName || ' ("DTTIME", "VALUE") VALUES (:1, :2)'; 

o Rastree su código para ver las declaraciones SQL reales que se activan en su database.

En primer lugar, no tiene un DONDE en su ACTUALIZACIÓN por lo que actualizará cada fila de la tabla.

En segundo lugar, has usado un nombre de tabla de caso mixto. Si haces una

 CREATE TABLE "testOne" (ID NUMBER); 

entonces el nombre de la tabla se almacenará como testOne. Pero cuando hagas una UPDATE testOne se tratará como UPDATE TESTONE y obtendrás un error de "no dicha tabla".

Evite usar nombres de tablas de casos mixtos. Si es absolutamente necesario, tendrá que citarlos en la statement SQL dinámica