plsql游标插入不同的模式

Posted

技术标签:

【中文标题】plsql游标插入不同的模式【英文标题】:plsql cursor insert into different schemas 【发布时间】:2017-07-17 09:33:59 【问题描述】:

我有 2 张桌子。 第一个表包含许多教室的学生 (姓名、年龄、班级)

另一个表包含每个班级的模式(教室,模式名称)

(所以每个班级都有不同的模式)

所以我对每个班级都有不同的架构。我需要从学生表中获取所有数据并将它们复制到正确模式的目标表中。 (我以管理员身份登录,我可以访问所有架构)

这是我的声明:

DECLARE
   CURSOR all_pupils
   IS
      SELECT NAME, AGE, CLAs-s-rOOM FROM TABLE_1
BEGIN
   FOR pupil_rec 
   IN  all_pupils
   LOOP
       EXECUTE IMMEDIATE 'INSERT INTO ' 
           || (Select schema_name FROM TABLE_2 sn WHERE sn.clas-s-room=pupil_rec.CLAs-s-rOOM) ||'.TARGET_TABLE ' 
         ||'(name, age) VALUES (pupil_rec.name, pupil_rec.age';
   END LOOP;
END;
/

我收到此错误:

PLS-00103: Encountered the symbol "END" when expecting one of the following:

我刚开始学习 PLSQL,有人告诉我必须用光标来学习。有人可以帮助我并告诉我这是否是正确的方法吗?我的结构似乎不正确..如何避免这些错误

【问题讨论】:

你不能在你喜欢的任何一行中间放一个(select ...)。您需要扩展光标以包含所需的值。 【参考方案1】:

EXECUTE IMMEDIATE 仅适用于静态字符串。因此,您需要先将架构名称查询到一个变量中,然后将该变量包含在您的语句中。

游标的内容也不在执行字符串的范围内。所以你需要通过占位符来传递它的值。

DECLARE
    CURSOR all_pupils
    IS
        SELECT NAME, AGE, CLAs-s-rOOM FROM TABLE_1;
    l_schema_name varchar2(30);
BEGIN
   FOR pupil_rec 
   IN  all_pupils
   LOOP
       Select schema_name 
       into l_schema_name 
       FROM TABLE_2 sn 
       WHERE sn.clas-s-room=pupil_rec.CLAs-s-rOOM:
       EXECUTE IMMEDIATE 'INSERT INTO ' 
           || l_schema_name  ||'.TARGET_TABLE ' 
           ||'(name, age) VALUES (:1, :2)'
           using pupil_rec.name, pupil_rec.age;
   END LOOP;
END;
/

或者,在驱动光标中使用连接...

DECLARE
    CURSOR all_pupils
    IS
        SELECT t1.NAME, t1.AGE, sn.schema_name  
        FROM TABLE_1 t1
             join TABLE_2 sn 
             on sn.clas-s-room = T1.CLAs-s-rOOM
        where t1.col_copied != 1
        for update of t1.col_copied ;
BEGIN
   FOR pupil_rec 
   IN  all_pupils
   LOOP
       EXECUTE IMMEDIATE 'INSERT INTO ' 
           || pupil_rec.schema_name  ||'.TARGET_TABLE ' 
           ||'(name, age) VALUES (:1, :2)'
           using pupil_rec.name, pupil_rec.age;

       update  TABLE_1 t1
       set t1.col_copied = 1
       where current of all_pupils;

   END LOOP;
END;
/

【讨论】:

我有一个额外的要求(抱歉,现在才发现)。我的 Table_1 有一个附加列 (COL_COPIED)。当该行被选择并复制到正确的模式中时,我需要将其设置为 1。因此,当再次执行该语句时,它只选择未复制的行(TABLE_1 将始终获取新数据)。我可以在我的 for 循环中执行一个附加语句(如插入)来进行更新吗?或者有没有更好的解决方案 非常感谢,只是一个问题(我试图理解您的陈述)您在开始时的连接会像您的第一个解决方案一样选择 table_1 中的所有数据(没有连接)。你刚刚使用了一个连接来引用循环内的 schema_name 对吗? 是的。一般来说,连接两个表比在循环中查找要好,因为集合操作比逐行处理更有效。这可能不会对您的情况产生太大影响,但养成好习惯永远不会太早 我在“当前的位置”行出现错误,它说缺少'('。并且此行不应以分号结尾:'(name,age)VALUES(:1,: 2)'; ? 嗯,不知道为什么您会收到 that 错误消息:您一定是打错字了。如果您正确翻译了我的示例,您将得到pls-00413,因为我引用了记录变量而不是游标名称(自更正后)。【参考方案2】:

需要一个新变量来保存架构名称。在Execute Immediate 内不能连接其他SELECT,除非它作为字符串提供。

DECLARE

    CURSOR all_pupils
    IS

        SELECT NAME,
            AGE,
            CLAs-s-rOOM
        FROM TABLE_1;

    v_chr_schema TABLE_2.schema_name%TYPE;
BEGIN

    FOR pupil_rec IN all_pupils
    LOOP

        SELECT schema_name
        INTO v_chr_schema
        FROM TABLE_2
        WHERE sn.clas-s-room=pupil_rec.CLAs-s-rOOM;

        EXECUTE IMMEDIATE 'INSERT INTO ' || v_chr_schema ||'.TARGET_TABLE ' ||
        '(name, age) VALUES (' || pupil_rec.name || ',' || pupil_rec.age || ')';

    END LOOP;

END;
/

【讨论】:

非常感谢,我根据您的输入更改了我的声明,但出现错误:00984. 00000 - “此处不允许列。 @Norbert94 - cursor 中的值应该在字符串之外。现在已在答案中修复

以上是关于plsql游标插入不同的模式的主要内容,如果未能解决你的问题,请参考以下文章

SQL记录-PLSQL游标

提高插入游标的性能?

PLSQL - 游标不能在动态 sql 中使用

PLSQL——04游标

『ORACLE』 PLSQL动态游标的使用(11g)

sql 游标如何循环