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

Posted

技术标签:

【中文标题】创建一个表,其中动态 PL/SQL 中的“日期条件”【英文标题】:Create a table as, where 'date condition' in dynamic PL/SQL 【发布时间】:2017-06-04 20:12:18 【问题描述】:

我被分配了以下任务。

假设我们有一个由 id 列和 date 列构成的表 A。 在 PL/SQL 中编写一个过程: 将表名(在我们的例子中为 A)和日期 D 作为参数,创建一个名为 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 条件而不是在日期一上使用 where 条件来实现相同的结果,我没有问题。 错误在哪里?我是否完全以错误的方式实施它?

【问题讨论】:

这听起来像是日期格式模型问题。到目前为止你做了什么? 并非所有人都可以访问外部链接。 【参考方案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);

编辑:评论后的进一步解释

为了解释为什么在使用整数时不会出现上述问题,重要的是要记住使用立即执行只是将给定字符串作为 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;

【讨论】:

现在一切都说得通了!因此,每次我需要创建动态 SQL 语句时,非字符串的变量必须用 '' 进行转义。错误地,我认为串联会自动完成这项工作。但是为什么如果变量是一个数字我没有得到任何错误呢? 添加了更多解释,希望为您添加一些说明 很好的解释。不过,我更喜欢'where table_date < date ''' || backup_date || ''''backup_date 格式的YYYY-MM-DD,而不是where table_date < date '2017-05-27'

以上是关于创建一个表,其中动态 PL/SQL 中的“日期条件”的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 PL/SQL 过程和表名作为变量打印动态 SQL 中的所有表行?

如何根据表名作为输入在 PL/Sql 中动态创建记录

使用 SQL 或 PL/SQL 对多个表中的列和表名进行动态查询

在 PL/SQL 过程中打开动态表名的游标

PL SQL - 使用动态 SQL 生成删除语句

带有动态 sql 的 PL/SQL 触发器