创建一个表,其中“动态PL / SQL中的日期条件”

时间:2017-06-04 20:12:18

标签: plsql dynamic-sql

我被分配了以下任务。

假设我们有一个带有id列和日期列的表A. 在PL / SQL中编写一个过程:将表名(在我们的例子中为A)和日期D作为参数,创建一个名为A_bck的备份表,其中只包含日期<的记录。 D并从表A中删除A_bck中插入的所有记录。

Here there is my code.

不幸的是我收到了这个错误:

Error report -
ORA-00904: "MAY": invalid identifier
ORA-06512: at line 41
ORA-06512: at line 80
00904. 00000 -  "%s: invalid identifier"

如果我尝试使用id列上的where条件而不是日期1来实现相同的结果,那么我没有问题。 哪里出错了?我是以完全错误的方式实施的吗?

1 个答案:

答案 0 :(得分:1)

你遇到的问题是,当你执行动态sql时,你的查询被构建为一个字符串。 Oracle不知道您提供的日期实际上是一个日期,它只是被视为字符串的一部分。要解决此问题,您应该能够执行以下操作:

my_query := 'CREATE TABLE ' || table_name_backup || ' AS (SELECT * FROM ' || table_name || ' WHERE table_date < to_date(''' || backup_date || '''))';

这应该为您解决问题。作为旁注,您可能希望更改“table_exists”查询,因为表名都以大写形式存储,例如

SELECT COUNT(*) INTO table_exists FROM USER_TABLES WHERE TABLE_NAME = upper(my_table);

编辑:评论后的进一步说明

要解释为什么在使用整数时没有上述问题,重要的是要记住使用execute immediate只是将给定的字符串作为SQL查询执行。

例如:

declare 
  x INTEGER := 1;
  i integer;
  my_query VARCHAR2(256);
begin
  my_query := 'select 1 from dual where 1 = ' || x;
  EXECUTE IMMEDIATE my_query INTO i;
end;
上面示例中的

my_query将执行为:

select 1 from dual where 1 = 1

这是完全有效的sql。然而,在你的例子中,你最终会得到这样的结论:

CREATE TABLE abaco_bck AS (SELECT * FROM abaco WHERE table_date < 27-MAY-17)

由于它没有用引号括起来,或者显式转换为日期,因此SQL引擎试图从27减去“MAY”,但它不知道“MAY”是什么。

还有一点需要注意的是,对于某些操作,您可以使用绑定变量而不是引号(尽管您不能使用DDL),例如。

declare 
  lToday    DATE := SYSDATE;
  i         INTEGER;
  my_query  VARCHAR2(256);
begin
  my_query := 'select 1 from dual where sysdate = :1';
  EXECUTE IMMEDIATE my_query INTO i USING lToday;
end;