【问题标题】:PLSQL Insert into with subquery and returning clausePLSQL插入带有子查询和返回子句
【发布时间】:2011-07-16 13:14:36
【问题描述】:

我不知道以下伪 sql 的正确语法:

INSERT INTO some_table
           (column1,
            column2)
     SELECT col1_value, 
            col2_value 
       FROM other_table
      WHERE ...       
  RETURNING id
       INTO local_var; 

我想用子查询的值插入一些东西。 插入后我需要新生成的 id。

这是 oracle 文档所说的:

Insert Statement

Returning Into

好的,我认为仅使用 values 子句是不可能的... 有其他选择吗?

【问题讨论】:

    标签: sql oracle plsql insert return-value


    【解决方案1】:

    您不能,但至少在 Oracle 19c 中,您可以在 VALUES 子句中指定 SELECT 子查询,因此使用 RETURNING!这可能是一个很好的解决方法,即使您可能必须为每个字段重复 WHERE 子句:

    INSERT INTO some_table
               (column1,
                column2)
         VALUES((SELECT col1_value FROM other_table WHERE ...),
                (SELECT col2_value FROM other_table WHERE ...))
      RETURNING id
           INTO local_var; 
    

    【讨论】:

      【解决方案2】:

      您不能使用 INSERT 中的 RETURNING BULK COLLECT。 但是,此方法可用于更新和删除:

      create table test2(aa number)
      /
      insert into test2(aa)
            select level
              from dual
              connect by level<100
      /        
      
      set serveroutput on
      declare 
           TYPE t_Numbers IS TABLE OF test2.aa%TYPE
              INDEX BY BINARY_INTEGER;
            v_Numbers t_Numbers;
            v_count number;
      begin
      
      
      update test2
        set aa = aa+1
      returning aa bulk collect into v_Numbers;
      
          for v_count in 1..v_Numbers.count loop
              dbms_output.put_line('v_Numbers := ' || v_Numbers(v_count));
          end loop;
      
      end;
      

      你可以通过几个额外的步骤让它工作(使用 TREAT 进行 FORALL INSERT) 如本文所述:

      returning with insert..select

      T

      利用他们创建的示例并将其应用于 test2 测试表

       CREATE or replace TYPE ot AS OBJECT
          ( aa number);
      /
      
      
      CREATE TYPE ntt AS TABLE OF ot;
      /
      
      set serveroutput on
       DECLARE
      
             nt_passed_in ntt;
             nt_to_return ntt;
      
             FUNCTION pretend_parameter RETURN ntt IS
                nt ntt;
             BEGIN
                SELECT ot(level) BULK COLLECT INTO nt
               FROM   dual
               CONNECT BY level <= 5;
               RETURN nt;
            END pretend_parameter;
      
         BEGIN
      
            nt_passed_in := pretend_parameter();
      
            FORALL i IN 1 .. nt_passed_in.COUNT
               INSERT INTO test2(aa)
               VALUES
               ( TREAT(nt_passed_in(i) AS ot).aa
               )
               RETURNING ot(aa)
               BULK COLLECT INTO nt_to_return;
      
            FOR i IN 1 .. nt_to_return.COUNT LOOP
               DBMS_OUTPUT.PUT_LINE(
                  'Sequence value = [' || TO_CHAR(nt_to_return(i).aa) || ']'
                  );
            END LOOP;
      
         END;
         /
      

      【讨论】:

      • 太酷了!留给我的唯一问题是声明对象类型。无法在包中声明对象类型...
      【解决方案3】:

      由于插入基于选择,Oracle 假设您允许使用该语法进行多行插入。在这种情况下,请查看返回子句文档的多行版本,因为它表明您需要使用 BULK COLLECT 将所有插入行中的值检索到结果集合中。

      毕竟,如果您的插入查询创建了两行 - 它会将哪个返回值放入单个变量中?

      编辑 - 事实证明这并不像我想象的那样工作......该死!

      【讨论】:

      • 我试过了,但我得到一个 ORA 009333。SQL 命令在 where 之后没有正确结束。集合类型是个好主意。
      • 正如托尼在他的回答中所说,BULK COLLECT 不适用于 INSERT - 至少在 10g 和更早版本中。我不清楚这在 11g 中是否发生了变化。
      • 是的,我认为这行得通,但似乎行不通。很抱歉给你不好的建议。
      【解决方案4】:

      很遗憾,这是不可能的。 RETURNING 仅适用于 INSERT...VALUES 语句。有关此主题的讨论,请参阅 this Oracle forum thread

      【讨论】:

        【解决方案5】:

        这并不像您想象的那么简单,当然也不像使用 MySQL 那样简单。 Oracle 不会以您可以 ping 回结果的方式跟踪最后的插入。

        你需要想出一些其他的方法来做到这一点,你可以使用 ROWID 来做到这一点 - 但这有它的缺陷。

        这个链接讨论了这个问题:http://forums.oracle.com/forums/thread.jspa?threadID=352627

        【讨论】:

        • 这与所提出的问题并不真正相关——它不是关于识别任何会话插入的最后一行,而是关于从特定的 INSERT 语句返回一组值。
        猜你喜欢
        • 1970-01-01
        • 2016-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-13
        • 1970-01-01
        • 1970-01-01
        • 2015-02-10
        相关资源
        最近更新 更多