问题描述
我有一个小程序,如果存在则应该截断分区
create or replace PROCEDURE drop_partition(p_table_name VARCHAR2,p_load_seq INTEGER)
AS
l_sql_text VARCHAR2(1000 CHAR);
l_part_exists NUMBER;
BEGIN
l_sql_text:= 'SELECT count(*) FROM user_tab_partitions where table_name=' || p_table_name ||' and high_value='||p_load_seq ;
EXECUTE IMMEDIATE l_sql_text INTO l_part_exists;
if (l_part_exists=1) THEN
l_sql_text := 'ALTER TABLE ' || p_table_name || ' DROP PARTITION FOR(' || to_char(p_load_seq) || ')';
EXECUTE IMMEDIATE l_sql_text;
END IF;
END;
如果我尝试运行这样的程序
call drop_partition('test',1);
有错误:
ORA-00904: "TEST": invalid identifier
ORA-06512: at "DROP_PARTITION",line 8
00904. 00000 - "%s: invalid identifier"
有什么问题,我该如何解决?
解决方法
您需要将表名括在单引号中,然后将其转义:
... where table_name=''' || p_table_name ||''' and ...
即:
l_sql_text:= 'SELECT count(*) FROM user_tab_partitions where table_name=''' || p_table_name ||''' and high_value='||p_load_seq ;
有一个alternative quoting mechanism消除了对引号进行转义的需要,但我认为这会更加令人困惑。
使用动态SQL时,在执行之前输出生成的语句以用于调试目的会很有用:
dbms_output.put_line(l_sql_text);
并在呼叫前在客户端中启用输出。
就像贾斯汀·凯夫(Justin Cave)正确指出的那样,过程的查询部分无论如何都不需要动态。您可以使用静态SQL:
SELECT count(*)
INTO l_part_exists
FROM user_tab_partitions
where table_name = p_table_name
and high_value = p_load_seq;
默认情况下,表名称之类的标识符在数据字典中为大写,因此您可以在该语句中使用upper(p_table_name)
(静态或动态);但是,如果确实有任何大小写混合的带引号的标识符,则可以改用调用方以正确的大小写传递名称:
drop_partition('TEST',1);
...假设您的test
表没有带引号的标识符。