在表创建脚本中使用变量

时间:2013-10-15 21:40:37

标签: oracle plsql oracle11g plsqldeveloper

我在创建PL / SQL块时遇到了一些困难。我的脚本的目的是根据表中的上个月的总计(已经创建为表名“countpull”)来提取报告。我想在我的脚本中使用月份名来创建表,但Oracle返回错误“ORA-00900:无效的SQL语句”,指向下面的CREATE TABLE命令。

DECLARE
  curMonthChar NVARCHAR2(25);
  curTableName NVARCHAR2(50);
  tableexists NUMBER := 0;

BEGIN
  SELECT TO_CHAR(ADD_MONTHS(sysdate,-1),'fmMONTH') INTO curMonthChar FROM DUAL;
  SELECT ('QP17414_'||curMonthChar) INTO curTableName FROM DUAL;

  --Check to see if current month's count table exists
  SELECT COUNT(1) INTO tableexists FROM all_tab_columns WHERE OWNER = (SELECT USER FROM DUAL) AND table_name = curTableName;

  --If current month's count table exists, drop it
  IF tableexists > 0 THEN
    EXECUTE IMMEDIATE 'DROP TABLE '||curTableName;
  END IF;

  --Create current month's count table
  EXECUTE IMMEDIATE '
  CREATE TABLE '||curTableName||' AS (
    SELECT * FROM (
      SELECT movetype, phone_flag, state FROM countpull
      )
    PIVOT (
      COUNT(state)
      FOR state IN ('''||'AA'||''','''||'AE'||''','''||'AK'||''','''||'AL'||'''
        ,'''||'AP'||''','''||'AR'||''','''||'AS'||''','''||'AZ'||''','''||'CA'||'''
        ,'''||'CO'||''','''||'CT'||''','''||'DC'||''','''||'DE'||''','''||'FL'||'''
        ,'''||'FM'||''','''||'GA'||''','''||'GU'||''','''||'HI'||''','''||'IA'||'''
        ,'''||'ID'||''','''||'IL'||''','''||'IN'||''','''||'KS'||''','''||'KY'||'''
        ,'''||'LA'||''','''||'MA'||''','''||'MD'||''','''||'ME'||''','''||'MH'||'''
        ,'''||'MI'||''','''||'MN'||''','''||'MO'||''','''||'MP'||''','''||'MS'||'''
        ,'''||'MT'||''','''||'NC'||''','''||'ND'||''','''||'NE'||''','''||'NH'||'''
        ,'''||'NJ'||''','''||'NM'||''','''||'NV'||''','''||'NY'||''','''||'OH'||'''
        ,'''||'OK'||''','''||'OR'||''','''||'PA'||''','''||'PR'||''','''||'PW'||'''
        ,'''||'RI'||''','''||'SC'||''','''||'SD'||''','''||'TN'||''','''||'TX'||'''
        ,'''||'UT'||''','''||'VA'||''','''||'VI'||''','''||'VT'||''','''||'WA'||'''
        ,'''||'WI'||''','''||'WV'||''','''||'WY'||''')
    ))';

END;

当我不尝试为表名使用变量时,上面的脚本运行正常。但是因为我希望每次运行脚本时动态更改表名,所以我想避免使用静态名称。

为什么在PL / SQL块中创建具有动态表名的表无效?

其他信息:

countpull的表架构是

state NVARCHAR2(2),
movetype NVARCHAR2(1),
phone_flag NVARCHAR2(1)

1 个答案:

答案 0 :(得分:2)

由于我不能立即明白的原因,问题是您使用的变量是nvarchar2。如果您将其声明为varchar2

,则可以使用它
  curTableName VARCHAR2(50);

通过SQL Fiddle验证;如果只是将表名变量的声明更改为nvarchar2,那么这个小提琴就会失败。

正如@jonearles指出的那样,documentation确实声明命令字符串的'类型必须是CHARVARCHAR2CLOB'。虽然the concatenation operator的文档没有引用它,但相关的concat function确实声明'如果其中一个参数是国家数据类型,则返回的值是国家数据类型' - 所以你的命令字符串是nvarchar2,因为你在串联中使用的变量是nvarchar2,这使得execute immediate语句的参数非法。

尽管创建表格并不是一个好主意。通常应该创建一次模式对象。你可以有一个表 - 可能是一个全局的临时表 - 带有一个月份列,或者推送十二个表,你可以根据需要清空和填充。

此外,您的所有select from dual语句都可以简化:

  curMonthChar := TO_CHAR(ADD_MONTHS(sysdate,-1),'fmMONTH');
  curTableName := 'QP17414_'||curMonthChar);

等,甚至在您的子查询中:

... WHERE OWNER = user AND ...

...我不知道你为什么在你的枢轴条款中使用这么多连接。