任何更好的UPSERT进入表格的方法,提供:
以下程序: “ORA-00942:表或视图不存在”
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";
答案 0 :(得分:4)
MERGE与Native动态SQL(EXECUTE IMMEDIATE)完美搭配:
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;
您能否发布使用MERGE时收到的错误消息?
答案 1 :(得分:2)
您应该考虑将其编写为使用静态SQL而不是在运行时传递表名。是否有正当理由说明为什么你不知道你将在什么时候合并到运行时间?
至于调试问题......
如何在代码中定义FGETTABLENAME函数?这就是我提出的模仿那种情况的方法。我建议使用%type(而不是数字类型的RAW)声明并从过程名称中删除双引号。
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
您可以在
之后将DBMS_OUTPUT.PUT_LINE语句添加到您的代码中vTableName := FGETTABLENAME(POBJECTID => pObjectID);
and
vQueryUpdate := 'UPDATE ' || vTableName || ' SET "VALUE" = :1';
vQueryInsert := 'INSERT INTO ' || vTableName || ' ("DTTIME", "VALUE") VALUES (:1, :2)';
或跟踪您的代码以查看向您的数据库触发的实际SQL语句。
答案 2 :(得分:2)
首先,您的UPDATE中没有WHERE,因此它会更新表的每一行。
其次,您是否使用了混合大小写表名称。如果你做了
CREATE TABLE "testOne" (ID NUMBER);
然后表名将存储为testOne。但是,如果您执行了UPDATE testOne
,则会将其视为UPDATE TESTONE
,并且您将收到“无此表”错误。
避免使用混合大小写表名称。如果你绝对必须,那么你需要在动态SQL语句中引用它们