在表创建脚本中使用变量
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 确实声明命令字符串的“类型必须是CHAR
、VARCHAR2
或CLOB
”。尽管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 而言,我不得不将其归结为养成了一个坏习惯,即没有足够注意使用正确的数据类型来满足需要。以上是关于在表创建脚本中使用变量的主要内容,如果未能解决你的问题,请参考以下文章