【问题标题】:Inserting Data into Related Oracle Tables and Maintain List of Identity values将数据插入相关 Oracle 表并维护标识值列表
【发布时间】:2015-01-25 05:54:21
【问题描述】:

我有一个由程序代码填充的数据暂存表。

TABLE BatchRecord{
    BatchRecordID NUMBER PRIMARY KEY,
    BatchID NUMBER, --Assigned by the procedural code
    RecordID NUMBER, --Relative to the batch
    FieldID NUMBER, --Assigned by the procedural code; FK to another table
    Value VARCHAR2(MAX)
    Instance NUMBER}

每个 BatchRecord 然后需要转换成三个相关的表:Records、RecordFields、FieldValues。

TABLE Record{
    RecordID NUMBER PRIMARY KEY,
    BatchID NUMBER, --Same from BatchRecords}

TABLE RecordFields{
    RecordFieldID NUMBER PRIMARY KEY,
    RecordID NUMBER, --FK from Records
    FieldID NUNBER --Same from BatchRecords}

TABLE FieldValues{
    RecordFieldID NUMBER PRIMARY KEY,
    Instance NUMBER PRIMARY KEY, --Same from BatchRecords
    Value VARCHAR2(MAX) --Same from BatchRecords}

在 SQL Server 中,我可以使用 MERGE 语句并使用 OUTPUT 捕获新插入的键来完成此操作:

CREATE TABLE #InsertedRecords(RecordID INT, NewRecordID INT);

MERGE INTO Records USING (
    SELECT RecordID
    FROM BatchRecords
    WHERE BatchID = @BatchID
    GROUP BY RecordID) AS BR ON 1 = 0
WHEN NOT MATCHED THEN
    INSERT (BatchID)
    VALUES (@BatchID)
    OUTPUT BR.RecordID, INSERTED.RecordID INTO #InsertedRecords;

RecordFields的插入也采用类似的方法,FieldValues中使用INSERT...SELECT语句插入。

但是,在 Oracle 中,不能在 MERGE 语句甚至 SELECT...INTO 语句中使用 RETURNING(相当于 OUTPUT)。

是否有一种方法可以在 Oracle 中完成相同的任务,同时避免 FORALL 循环,因为 BatchRecord 的总数可能超过几百万?

【问题讨论】:

    标签: oracle bulkinsert oracle12c sql-returning


    【解决方案1】:

    您可以尝试使用 oracle PIPELINE 函数从 BatchRecord 中选择所有记录,然后将行通过管道传输到不同的表中。如果需要,我可以举个例子。

    编辑

    create or replace package test_pkg AS
    
      TYPE REP_CURS IS REF CURSOR;
      TYPE output_REC IS RECORD(
        RecordID_    number,
        BatchID_  number);
    
      TYPE output_TAB IS TABLE OF output_REC;
    
      FUNCTION Get_Data RETURN output_TAB
        PIPELINED;
    
    END test_pkg;
    
    CREATE OR REPLACE PACKAGE BODY test_pkg IS
    
      FUNCTION Get_Data RETURN output_TAB
        PIPELINED IS
    
        output_REC_ output_REC;
        rep_lines_  REP_CURS;
        stmt_       VARCHAR2(5000);
        table_rec_  BatchRecord%ROWTYPE;
    
      begin
        stmt_ := '  (select BatchRecordID,BatchID ....Instance  from BatchRecord)  ';
    
        OPEN rep_lines_ FOR stmt_;
        LOOP
          FETCH rep_lines_
            INTO table_rec_;
          EXIT WHEN rep_lines_%NOTFOUND;
    
          output_REC_.RecordID_   := <<whatever valu that you want>;
          output_REC_.BatchID_ := table_rec_.BatchID;
    
    
            PIPE ROW(output_REC_);
    
        END LOOP;
        CLOSE rep_lines_;
    
        RETURN;
      exception
        when others then
          DBMS_OUTPUT.put_line('Error:' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE ||
                               DBMS_UTILITY.FORMAT_ERROR_STACK ||
                               DBMS_UTILITY.FORMAT_CALL_STACK);
      END Get_Data;
    
    END test_pkg;
    

    我已经展示了一个插入记录的示例。您也必须对其他两个表进行类似操作。希望这会有所帮助!

    【讨论】:

    • 你能举个例子吗?
    • 我已编辑解决方案以包含示例。看看吧。
    • 这个方法仍然需要你遍历 BatchRecords 中的所有行。既然这个表可以有几百万行,有什么方法可以避免循环吗?
    猜你喜欢
    • 1970-01-01
    • 2014-02-16
    • 2012-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多