创建一个 table as,其中 'date condition' in dynamic PL/SQL
Create a table as, where 'date condition' in dynamic PL/SQL
我被分配了以下任务。
假设我们有一个 table A 结构,其中包含一个 id 列和一个 date 列。
在 PL/SQL 中编写一个过程:将 table 名称(在我们的示例中为 A)和日期 D 作为参数,创建一个名为 A_bck 的备份 table,仅包含记录日期 < D 的 A 并从 table A 中删除所有插入 A_bck.
的记录
不幸的是我得到了这个错误:
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 条件来获得相同的结果,我没有问题。
错误在哪里?我是否完全以错误的方式实施它?
您遇到的问题是,当您执行动态 sql 时,您的查询是作为字符串构建的。 Oracle 不知道您给出的日期实际上是一个日期,它只是被视为字符串的一部分。要解决此问题,您应该能够执行以下操作:
my_query := 'CREATE TABLE ' || table_name_backup || ' AS (SELECT * FROM ' || table_name || ' WHERE table_date < to_date(''' || backup_date || '''))';
这应该可以解决您的问题。作为旁注,您可能想要更改 "table_exists" 查询,因为 table 名称全部以大写形式存储,例如
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;
我被分配了以下任务。
假设我们有一个 table A 结构,其中包含一个 id 列和一个 date 列。 在 PL/SQL 中编写一个过程:将 table 名称(在我们的示例中为 A)和日期 D 作为参数,创建一个名为 A_bck 的备份 table,仅包含记录日期 < D 的 A 并从 table A 中删除所有插入 A_bck.
的记录不幸的是我得到了这个错误:
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 条件来获得相同的结果,我没有问题。 错误在哪里?我是否完全以错误的方式实施它?
您遇到的问题是,当您执行动态 sql 时,您的查询是作为字符串构建的。 Oracle 不知道您给出的日期实际上是一个日期,它只是被视为字符串的一部分。要解决此问题,您应该能够执行以下操作:
my_query := 'CREATE TABLE ' || table_name_backup || ' AS (SELECT * FROM ' || table_name || ' WHERE table_date < to_date(''' || backup_date || '''))';
这应该可以解决您的问题。作为旁注,您可能想要更改 "table_exists" 查询,因为 table 名称全部以大写形式存储,例如
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;