0

テーブルに UPSERT するためのより良い方法は次のとおりです。

  • ~1 行/秒でのデータ アップサート
  • テーブル名は動的で、渡された ObjectID パラメータを使用して生成されます

次の手順では、「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";
  • どうやら MERGE は TableName が動的にできないため機能しませんか???
  • 私は初心者で、コーディングを始めて 3 か月目です。現在 3 日間、STACKOVERFLOW と Google で検索し、あらゆる種類の面白くて絶望的な解決策を試しています。
4

3 に答える 3

4

MERGE は、ネイティブの動的 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 を使用したときに表示されるエラー メッセージを投稿していただけますか?

于 2011-07-20T13:10:37.687 に答える
2

実行時にテーブル名を渡すのではなく、静的SQLを使用するようにこれを作成することを検討する必要があります。実行時までマージするテーブルがわからない正当な理由はありますか?

問題のデバッグに関しては...

関数FGETTABLENAMEはコードでどのように定義されていますか?これは私が思いついたもので、そのシナリオを模倣しています。(数値タイプのRAWの代わりに)%type宣言を使用し、プロシージャ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

後に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ステートメントを確認します。

于 2011-07-20T13:24:27.793 に答える
2

まず、UPDATE に WHERE がないため、テーブルのすべての行が更新されます。

次に、大文字と小文字が混在するテーブル名を使用していませんか。あなたがする場合

CREATE TABLE "testOne" (ID NUMBER);

テーブル名はtestOneとして保存されます。ただし、これを行うとUPDATE testOneis として扱われUPDATE TESTONE、「そのようなテーブルはありません」というエラーが発生します。

大文字と小文字が混在するテーブル名は使用しないでください。絶対に必要な場合は、動的 SQL ステートメントでそれらを引用する必要があります

于 2011-07-21T00:11:12.763 に答える