我在创建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)
答案 0 :(得分:2)
由于我不能立即明白的原因,问题是您使用的变量是nvarchar2
。如果您将其声明为varchar2
:
curTableName VARCHAR2(50);
通过SQL Fiddle验证;如果只是将表名变量的声明更改为nvarchar2
,那么这个小提琴就会失败。
正如@jonearles指出的那样,documentation确实声明命令字符串的'类型必须是CHAR
,VARCHAR2
或CLOB
'。虽然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 ...
...我不知道你为什么在你的枢轴条款中使用这么多连接。