【问题标题】:PL/SQL Dynamic SQL : Table name not validPL/SQL 动态 SQL:表名无效
【发布时间】:2021-05-09 16:00:13
【问题描述】:

我目前正在学习 PL/SQL。我需要创建一个 PL/SQL 块来创建我所有表的备份,如下所示:myTable -> myTable_old。

这是我现在得到的:

DECLARE
Cursor c IS SELECT table_name 
            FROM user_tables 
            WHERE table_name NOT LIKE '%_old';
sql_slc VARCHAR2(200);
sql_drp VARCHAR2(200);
sql_crt VARCHAR2(200);
row_count NUMBER;
t_name user_tables.table_name%type;
t_backup_name user_tables.table_name%type;

BEGIN
    sql_drp := 'DROP TABLE :1 CASCADE';
    sql_crt := 'CREATE TABLE :1 AS SELECT * FROM :2';
    sql_slc := 'SELECT COUNT(*) FROM user_tables WHERE table_name = :1';
    OPEN c;
    LOOP
        FETCH c INTO t_name;
        EXIT WHEN (c%NOTFOUND);
        t_backup_name := t_name || '_old';
        dbms_output.put_line(t_name || ' ' || t_backup_name);
        
        EXECUTE IMMEDIATE sql_slc INTO row_count USING t_backup_name;
        IF row_count > 0 THEN
            dbms_output.put_line(t_backup_name || ' dropped');
            EXECUTE IMMEDIATE sql_drp USING t_backup_name;
        END IF;
        dbms_output.put_line(t_backup_name || ' created');
        EXECUTE IMMEDIATE sql_crt USING t_backup_name, t_name;
        COMMIT;
    END LOOP;
    CLOSE c;
END;
/

这是错误:

OUVRAGE OUVRAGE_old
OUVRAGE_old created
DECLARE
*
ERROR on line 1 :
ORA-00903: table name not valid
ORA-06512: on line 29

我不明白为什么会出现这个错误,有人可以帮助我吗?

【问题讨论】:

  • 它可能已经失败,因为 t_name 的长度大约是 32,所以添加“_old”使其太长而无法被数据库接受。 (取决于数据库版本)
  • 下一个崩溃的表的名称是“AUTEUR_OUVRAGE”,如果添加 _old 在长度上仍然不如 VARCHAR2(30)... 我仍然尝试将 t_name 和 t_backup_name 更改为 VARCHAR2(30 ) 并没有改变。
  • 我看到它说第 29 行发生了错误,但仍然尝试注释掉第一个执行立即语句并再次运行该块。我们看看哪里出错了
  • 如果 row_count > 0,它在第二次执行(删除)时崩溃,并且每次在第三次执行(创建表)时崩溃。
  • 然后进行另一个测试。将最后一个“立即执行”替换为以下开始 EXECUTE IMMEDIATE sql_crt USING t_backup_name, t_name;其他人则异常 dbms_output.put_line('t_backup_name: ' || t_backup_name || ' t_name: ' || t_name);返回;结尾;让我们看看它输出了什么

标签: sql oracle plsql dynamic-sql


【解决方案1】:

问题是您不能对表名使用绑定变量; Oracle documentation:

数据库只使用绑定变量的值,并且 不得以任何方式解释其内容。

您应该编辑您的代码以使用串联:

DECLARE
  Cursor c IS SELECT table_name 
              FROM user_tables 
              WHERE table_name NOT LIKE '%_OLD';           /* OLD, upper case */  
  sql_slc VARCHAR2(200);
  --sql_drp VARCHAR2(200);
  --sql_crt VARCHAR2(200);
  row_count NUMBER;
  t_name user_tables.table_name%type;
  t_backup_name user_tables.table_name%type;
BEGIN
--   sql_drp := 'DROP TABLE :1 CASCADE';   
--   sql_crt := 'CREATE TABLE :1 AS SELECT * FROM :2';
   sql_slc := 'SELECT COUNT(*) FROM user_tables WHERE table_name = :1';
   

   OPEN c;

   LOOP
      FETCH c INTO t_name;

      EXIT WHEN (c%NOTFOUND);
      t_backup_name := t_name || '_OLD';                                        /* OLD, upper case */
      DBMS_OUTPUT.put_line (t_name || ' ' || t_backup_name);

      EXECUTE IMMEDIATE sql_slc INTO row_count USING t_backup_name;

      IF row_count > 0
      THEN
         DBMS_OUTPUT.put_line (t_backup_name || ' dropped');

--         EXECUTE IMMEDIATE sql_drp USING t_backup_name;
         EXECUTE IMMEDIATE ' drop table ' || t_backup_name;                     /* concatenation and not bind variables */
      END IF;

      DBMS_OUTPUT.put_line (t_backup_name || ' created');                       /* concatenation and not bind variables */
--      EXECUTE IMMEDIATE sql_crt USING t_backup_name, t_name;
      EXECUTE IMMEDIATE 'create table ' || t_backup_name || ' as select * from ' || t_name;

      COMMIT;
   END LOOP;

   CLOSE c;
END;

另外,请注意,如果不是双引号,对象名称总是大写,所以你必须寻找t_name || '_OLD' 而不是t_name || '_old'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-29
    • 2012-04-03
    相关资源
    最近更新 更多