【问题标题】:generate sequence when inserting results from other table result set Oracle从其他表结果集Oracle插入结果时生成序列
【发布时间】:2018-08-23 03:33:18
【问题描述】:

我有一个来自表“test_inter”的选择语句的结果集。 我使用它在具有 id 的其他表中插入条目(按序列递增),同时从结果集插入循环中,我收到错误

 --Edit starts

        BEGIN

            l_sql := 'select null as rid,null as  rtype, null as sid,null as cid, null as  pid,mid ,name, origin ,ctry, instyle,null as mapct,null as defspct,null as addspct,null as opct ';


            FOR i IN 1 .. n_vers
            LOOP
                l_sql := l_sql || ', max( case when verorder = ' || i || ' then hoing else 0 end ) as h' || i;
                l_sql := l_sql || ', max( case when verorder = ' || i || ' then hoingpct else 0 end ) as p' || i;
            END LOOP;
            FOR i IN n_vers + 1 .. max_vers
            LOOP
                l_sql := l_sql || ', max( case when verorder = ' || i || ' then hoing else null end ) as h' || i;
                l_sql := l_sql || ', max( case when verorder = ' || i || ' then hoingpct else null end ) as p' || i;
            END LOOP;
            l_sql := l_sql || ', rowgroup,  sid,null as sname, null as hoingorder, null as plead, null as cneutral, null as notnullcol,null as notnullcolindex, null as SECPCT from
        (select mid ,name, origin ,ctry, instyle ,cid, cverid,  verorder, hoingpct, hoing,rowgroup,sid
        from test_inter
        where  rid = ' || n_rid || ' and sid = ''' || c_sid || '''  and rtype = ' || n_rtype || ' and pid = ' || n_pid || ' order by verorder  ) group by  mid ,name, origin ,ctry, instyle,rowgroup,sid ';

--n _vars and max_vars are constant values
           -- Edit Ends


            EXECUTE immediate l_sql;   -- gives me result set
                OPEN rc FOR l_sql;
                LOOP
                    FETCH rc INTO cp_row;
                    IF rc%FOUND THEN
                        INSERT
                        INTO test_final
                            (   
                                id     ,  --: ORA-01007: variable not in select list"
                                rid    ,
                                rtype  , 
                             -- more fields
                            )VALUES
                            (  seq.nextval,
                               cp_row.rid,
                               cp_row.rtype,
                               -- more values);
                    ELSE
                        EXIT;
                    END IF;
                    --exit when rc%NOTFOUND;
                END LOOP;
                CLOSE rc;   

        END;

我收到错误“原因:java.sql.SQLException:ORA-01007:变量不在选择列表中”,而我正在尝试生成 id 并插入它。 我还需要插入序列,当在表 test_final 中插入任何行时,我该怎么做?这方面的任何线索都会有所帮助。

编辑 2

我的问题和这个问题差不多

Sequence within SQL Select

我想为表“test_final”生成序列,但我无法使用 nextval。

谢谢

【问题讨论】:

  • 为什么要使用动态SQL? l_sql 到底是什么?你不能直接在游标 FOR 循环中使用它并做你正在做的事情吗?或者,更好的是,完全避免循环和/或 PL/SQL,并在 SQL 级别使用单个 INSERT 语句完成所有操作?
  • 我不想混淆,所以没有添加 select 语句是如何从 l_sql 构建的。我已经编辑了问题并添加了那部分。 'select' 语句不是直截了当的,所以我认为单个插入语句在这里是不可能的。请建议。谢谢
  • 关于顺序,假设您使用的是 12.1 或更高版本,给表格一个 identity column 并忘记它可能会更简单。

标签: oracle for-loop sequence


【解决方案1】:

当 SELECT 语句的投影包含与目标不同数量的列时,Oracle 会抛出 ORA-01007

在您的情况下,有 两个 地方可能会引发此异常:

  • 动态SQL语句的投影与cp_row的记录类型声明不匹配
  • insert into test_final (...) 中的列列表与select ... 中的列列表不匹配。

您已将 INSERT 语句指示为失败的行,但两条语句彼此相邻,并且动态 SQL 更难正确处理。事实上,我越看你的代码越有可能动态 SQL 是问题所在。

你的代码是这样做的:

FOR i IN 1 .. n_vers
LOOP
    l_sql := l_sql || ', max( case when verorder = ' || i || ' then hoing else 0 end ) as h' || i;
    l_sql := l_sql || ', max( case when verorder = ' || i || ' then hoingpct else 0 end ) as p' || i;
END LOOP;
FOR i IN n_vers + 1 .. max_vers
LOOP
    l_sql := l_sql || ', max( case when verorder = ' || i || ' then hoing else null end ) as h' || i;
    l_sql := l_sql || ', max( case when verorder = ' || i || ' then hoingpct else null end ) as p' || i;
END LOOP;

这意味着动态 SELECT 中的最终列数将根据 max_vers 的值而变化。 RECORD TYPE 的项目如何处理这种可变性?


[我]:seq.nextval 映射到 id 不是吗?
[op]: 是的,在 test_final 表中。但是 select 语句没有任何 id

福特。它有 seq.nextval 代替。我使用insert into whatever select seq.nextval, 结构已经超过二十五年了。那不是问题。问题是 SELECT 子句的投影与目标投影不匹配。

但不是 INSERT 语句的预测。如果问题是 INSERT 语句,Oracle 会抛出 ORA-00947: not enough valuesORA-00913: too many values(取决于哪个投影是不平衡的)。

问题是将生成的 SELECT 提取到 cp_row 变量中

这是SQL Fiddle 上的mcve,表明您的动态 SQL 语句是问题所在。第一次运行成功,因为 SELECT 语句的投影与 RECORD 类型的声明相匹配。第二次运行失败,因为 SELECT 语句具有不同的投影。

我们收到ORA-01007 错误,因为它是动态 SQL。静态 SQL 会产生无可辩驳的

ORA-06504:PL/SQL:结果集变量或查询的返回类型不匹配

动态 SQL 很难,因为它会将编译错误转化为运行时错误,而且很难调试。您需要做的是在执行之前(或不执行)显示l_sql 变量。然后您可以将生成的投影与记录类型的声明进行比较,并发现不一致之处。

【讨论】:

  • 是的,我知道情况确实如此。我想在 test_final 中插入 select 语句中不存在的序列(主键)。
  • 我想知道,我是怎么做到的。从错误语句“ ORA-01007:变量不在选择列表中”,我清楚地知道选择和插入参数不匹配。非常感谢。
  • 在 'insert' 语句中,这个 seq.nextval 引起了问题。我需要在 test_final 表中插入下一个序列作为主键。
  • seq.nextval 映射到 id 不是吗?
  • 是的,在test_final table中。但是select statment没有任何id
【解决方案2】:

啊哈。所以,l_sql 是一个 SELECT 语句。我不知道它最终合成时的样子,但是 - 我想你检查过它运行正常。如果是这样,这里有一个想法:

  • 创建一个(全局临时)表(我们称之为gtt_sql),其中包含l_sql 查询返回的所有列
  • 而不仅仅是选择,使用l_sql 作为insert into gtt_sql 的来源(你会使用execute immediate
  • 一旦表格中有数据,请重写当前代码,例如

-- this substitutes everything you put between `OPEN` and `CLOSE` cursor commands
for cur_r in (select column_list from gtt_sql) loop
  insert into test_final ...
end loop;

【讨论】:

  • 非常感谢您的快速回复。除了创建另一个临时表之外,还有什么办法吗?否则,我将不得不尝试这个。谢谢。
  • 您可以使用集合,但是 - 从我的角度来看,GTT 更简单。
  • 我不明白为什么 GTT 会让这个问题消失。问题是 SELECT 投影与 INSERT 投影不匹配。从 GTT 中选择而不是从记录变量中选择有什么区别?
  • 它不会消失,但它可能有助于更容易地看到正在发生的事情。当数据在表格中时,您可以从中进行选择,并在几秒钟内查看您拥有的内容。使用记录变量,这是一项乏味的工作(根据“更多价值”说明,OP 似乎没有发布他们拥有的 所有内容)。我只是觉得这样的复杂 l_sql 很难跟上。此外,如果它真的是 GTT,那么就没有必要循环通过它 - 一个简单的 INSERT INTO test final SELECT FROM gtt 就可以了。
  • 问题是动态 SQL 到变量中的提取,而不是插入。这里是a SQL Fiddle which reproduces the error
【解决方案3】:

作为选择(结果集)和插入语句(插入序列)之间不匹配的下一步,我尝试将 nextval 与“选择”语句一起使用。 但由于 'Select' 有 group by 子句,所以我无法将 nextval 放在 'select' 语句上。

我已经使用以下代码进行了此操作: l_sql := 'SELECT q.*, sh_rpt_temp_peer_final_seq.nextval as id FROM (' || l_sql || ') q';

我正在接受这个帖子的答案:

Sequence within SQL Select

谢谢。

【讨论】:

  • 所以您在问题中发布的所有代码都与您抱怨的 ORA-01007 无关?那是我生命中的一个小时,我不会回来。
  • @APC,正如我在问题中发布的那样 1)我最初在插入语句中使用 seq.nextval 时遇到此错误,但在 select 语句中没有此字段。(不匹配) 2)然后我在select语句中添加了seq.nextval,如我的答案所示,然后它解决了我的答案。我赞成您和 Littlefoot 的评论,这有助于我思考整个过程。非常感谢 APC。非常感谢您的回复。
猜你喜欢
  • 1970-01-01
  • 2021-08-27
  • 2021-08-29
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-13
相关资源
最近更新 更多