在表创建脚本中使用变量

Posted

技术标签:

【中文标题】在表创建脚本中使用变量【英文标题】:Using a Variable in a Table Creation Script 【发布时间】:2013-10-15 21:40:37 【问题描述】:

我在创建 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】:

由于我不清楚的原因,问题在于您使用的变量是nvarchar2。如果您将其声明为varchar2,则它可以工作:

  curTableName VARCHAR2(50);

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

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

不过,动态创建表格并不是一个好主意。 Schema 对象通常应该创建一次。你可以有一个表 - 可能是一个全局临时表 - 有一个月份列,或者按需要清空并填充十二个表。

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

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

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

... WHERE OWNER = user AND ...

...我不知道您为什么在枢轴子句中使用如此多的连接。

【讨论】:

manual 没有解释原因,它只是说动态 SQL 字符串“...必须是 CHAR、VARCHAR2 或 CLOB。” @jonearles - 谢谢 - 我在另一个选项卡中打开了该部分,但仍然看不到它。我还添加了用于连接的文档链接,使整个动态字符串 nvarchar2 也一样,这也不是很明显。 谢谢 Alex,这似乎是问题所在。这是我从 SQL Server 切换后第一次真正涉足 PL/SQL,所以我有很多东西要学。我的枢轴中的连接是我为试图找出我的 SQL 的“无效”内容而采取的许多步骤的结果。我认为我一定是错误地设置了枢轴。也感谢您简化建议。就使用 nvarchar2 而言,我不得不将其归结为养成了一个坏习惯,即没有足够注意使用正确的数据类型来满足需要。

以上是关于在表创建脚本中使用变量的主要内容,如果未能解决你的问题,请参考以下文章

在表中输入数据时运行小脚本

基本脚本编译------------(创建脚本与使用变量)

如何在shell脚本中使用变量

变量的转移到查询Pentaho。

如何仅删除由特定 matlab 脚本创建的变量

如何在 psql 中使用脚本变量?