【问题标题】:Select table in cursor after creating the table创建表后在光标中选择表
【发布时间】:2020-01-28 10:31:03
【问题描述】:

只是想寻求帮助,我创建了一个脚本,它将首先检查表是否已经存在。如果表不存在,那么我需要创建一个表,然后我将在光标中选择它。我只需要创建一次表,然后如果表存在,我应该只插入数据。这应该只是一个 sql 脚本中的地址。

问题是当我尝试执行我的脚本时,它显示“表或视图不存在”,似乎当我运行我的脚本时光标正在尝试验证它。有没有办法解决这个问题?

DECLARE 
tbl_exist_s1 PLS_INTEGER;
tbl_exist_s2 PLS_INTEGER;
total_were_updated_sc2 NUMBER(10,0);
total_need_to_update_sc2 NUMBER(10,0);
total_were_updated_sc1 NUMBER(10,0);
total_need_to_update_sc1 NUMBER(10,0);
run_date Date := SYSDATE;


BEGIN

  DBMS_OUTPUT.ENABLE(NULL);
  --Checking if the table is already existing, create table if not existing.
  select count(*) into tbl_exist_s2
  from all_tables
  where owner = 'cent' AND table_name = 'serv_req';

  DBMS_OUTPUT.PUT_LINE('Cleanup run: ' || SYSDATE);

  if (tbl_exist_s2 = 0) THEN
     DBMS_OUTPUT.PUT_LINE('Start Creating table cent.serv_req');

    EXECUTE IMMEDIATE 'CREATE TABLE cent.serv_req (      
    association_type NUMBER(10,0), 
    association_id NUMBER(10,0), 
    association_id_serv NUMBER(10,0),
    request_id NUMBER(10, 0)
    record_audit_datet DATE,

    CONSTRAINT pk_sc1 PRIMARY KEY(association_type, association_id, association_id_serv))';
END IF;

-- this is to insert the new data to the table.
EXECUTE IMMEDIATE 'INSERT INTO cent.serv_req
      VALUES(12, 13, 14, 1172, SYSDATE)';
commit;

 DECLARE
 v_err_comp CHAR(2000);
 c SYS_REFCURSOR;

 CURSOR sample_cursor IS
 select *
 from cent.serv_req
 where record_audit_date = run_date;

 sample_cursor_rec sample_cursor%ROWTYPE;
 BEGIN
   -- This will count the no of the records that are getting updated
   total_need_to_update_sc2 := 0;
   total_were_updated_sc2 := 0;

   DBMS_OUTPUT.PUT_LINE('===Starting process to activate the component element record associated to the active member instance record===');

-- this loop is to update the component element
OPEN sample_cursor ;
  LOOP
    FETCH sample_cursor INTO sample_cursor_rec;
      EXIT WHEN sample_cursor % NOTFOUND;

       DBMS_OUTPUT.PUT_LINE('===sample===');
        --Logic should be here
    END;

  END LOOP;
CLOSE sample_cursor;
END;

END;

【问题讨论】:

    标签: oracle oracle-sqldeveloper plsqldeveloper


    【解决方案1】:

    Oracle 必须先编译该块,然后才能运行它。编译块的一部分是验证所有引用的对象是否存在,这对您来说是失败的,因为表不存在。有两种基本方法。

    • 您可以将脚本分成两个单独的 PL/SQL 块。如果表不存在,则第一个创建表。然后第二个实现您想要实现的任何逻辑。
    • 如果您需要将其作为单个 PL/SQL 块,则必须在引用该表的任何地方使用动态 SQL。您可以使用动态 SQL 语句打开游标和/或使用 dbms_sql package 运行后续查询。但是,这会给您的代码增加相当多的复杂性,因此通常并不理想。

    【讨论】:

    • 我试图将它们分成 2 个 PL/SQL 块,但是当我运行它们时,光标仍在寻找表。
    【解决方案2】:

    看看以下是否有帮助。这是您的代码的摘录:

    select count(*) into tbl_exist_s2
    from all_tables
    where owner = 'cent' AND table_name = 'serv_req';     --> this
    
    <snip>
    
    EXECUTE IMMEDIATE 'CREATE TABLE cent.serv_req (       --> this
    
    <snip>
    
    EXECUTE IMMEDIATE 'INSERT INTO cent.serv_req          --> this
    

    默认情况下,Oracle 以 大写 存储对象名称(包括所有者名称、表名称、列名称……)。

    因此,SELECT 运行返回 0,因为它确实没有找到名称为 serv_req(小写)的表,该表由用户 cent(再次小写)拥有。

    然后,使用动态 SQL,您尝试创建一个表并将其插入其中,但这次“通常”引用它(即 cent.serv_req),这由 Oracle 正确解释;除非表名包含在双引号中(因此混合 CAsE 很重要),否则 Oracle 知道该做什么。

    很快:尝试在第一次选择中切换到UPPERCASE,即

    select count(*) into tbl_exist_s2
    from all_tables
    where owner = 'CENT' AND table_name = 'SERV_REQ';     --> this; use UPPERCASE
    

    此外,您不能引用尚不存在的表 - 这就是您的 CURSOR 正在尝试做的事情。如果你想这样做,你将不得不再次切换到动态 SQL,这正在慢慢变成一场噩梦。

    这是你的代码,经过修改,实际上可以编译并做一些事情

    第一部分:

    SQL> declare
      2    tbl_exist_s1             pls_integer;
      3    tbl_exist_s2             pls_integer;
      4    --total_were_updated_sc2   NUMBER(10,0);     --> moved to ...
      5    --total_need_to_update_sc2 NUMBER(10,0);     --> ... another PL/SQL ...
      6    total_were_updated_sc1   number(10,0);
      7    total_need_to_update_sc1 number(10,0);
      8    --run_date                 Date := SYSDATE;  --> ... block
      9  begin
     10    dbms_output.enable(null);
     11    --Checking if the table is already existing, create table if not existing.
     12    select count(*) into tbl_exist_s2
     13      from all_tables
     14      where owner = 'SCOTT' and table_name = 'SERV_REQ';
     15
     16      dbms_output.put_line('Cleanup run: ' || sysdate);
     17
     18    if (tbl_exist_s2 = 0) then
     19       dbms_output.put_line('Start Creating table cent.serv_req');
     20
     21       execute immediate 'CREATE TABLE scott.serv_req (
     22         association_type    NUMBER(10,0),
     23         association_id      NUMBER(10,0),
     24         association_id_serv NUMBER(10,0),
     25         request_id          NUMBER(10,0),          --> missing comma here
     26         record_audit_date   DATE,
     27         CONSTRAINT pk_sc1 PRIMARY KEY(association_type,
     28                                       association_id,
     29                                       association_id_serv))';
     30    end if;
     31
     32    -- this is to insert the new data to the table.
     33    execute immediate 'INSERT INTO scott.serv_req
     34        VALUES(12, 13, 14, 1172, SYSDATE)';
     35    commit;
     36  end;
     37  /
    Cleanup run: 09/28/2019
    Start Creating table cent.serv_req
    
    PL/SQL procedure successfully completed.
    
    SQL>
    

    第二部分:

    SQL> -- This should be a new PL/SQL procedure as you can't reference table that
    SQL> -- doesn't exist (yet)
    SQL> declare
      2    total_were_updated_sc2   number(10,0);
      3    total_need_to_update_sc2 number(10,0);
      4    run_date                 date := sysdate;
      5
      6    v_err_comp               char(2000);
      7    c                        sys_refcursor;
      8
      9    cursor sample_cursor is
     10      select *
     11      from scott.serv_req
     12      where record_audit_date = run_date;
     13
     14    sample_cursor_rec sample_cursor%rowtype;
     15  begin
     16    -- This will count the no of the records that are getting updated
     17    total_need_to_update_sc2 := 0;
     18    total_were_updated_sc2 := 0;
     19
     20    dbms_output.put_line('===Starting process to activate the component element record associated to the active member instance record===');
     21
     22    -- this loop is to update the component element
     23    open sample_cursor ;
     24    loop
     25      fetch sample_cursor into sample_cursor_rec;
     26      exit when sample_cursor % notfound;
     27
     28      dbms_output.put_line('===sample===');
     29      --Logic should be here
     30      --END;  --> this doesn't have its BEGIN; remove it
     31    end loop;
     32    close sample_cursor;
     33  end;
     34  /
    ===Starting process to activate the component element record associated to the active member instance record===
    
    PL/SQL procedure successfully completed.
    
    SQL>
    

    在我看来,你应该考虑一下。不要动态创建表,这不是一个好主意。使用纯 SQL 创建一次,以后可以根据需要多次使用。动态 SQL 很高兴拥有,但它无法扩展,难以调试,容易长成怪物,让您(作为开发人员)的生活变得悲惨。

    【讨论】:

    • 我已经看到有另一种定义像游标的方法。我阅读了关于在光标中声明我的选择,将其放在“打开”上,如下所示:“打开 sample_cursor FOR '' select * from cent.serv_req where record_audit_date = run_date”,但似乎当我使用它时,我需要为每一列声明一个变量只是为了在循环中访问它?对这个有什么想法吗?
    • 看看 refcursor 是否有帮助。
    猜你喜欢
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-20
    • 1970-01-01
    • 2014-05-22
    相关资源
    最近更新 更多