我正在尝试实现一个简单的过程来计算给定字段的不同值的比例,并将结果存储在辅助表中。
CREATE TABLE TEST_DATA_QTY_AND
(
TABLE_ID VARCHAR2(30),
FLD_ID VARCHAR2(30),
MEASURE NUMBER(1, 2),
DATA_T DATE DEFAULT SYSDATE,
NOTES VARCHAR2(255)
);
CREATE OR REPLACE PROCEDURE DATA_QTY_AND(pTable IN VARCHAR2, pField IN VARCHAR2)
IS
v_sql varchar2(2000);
v_sql := 'INSERT INTO TEST_DATA_QTY_AND (TABLE_ID, FLD_ID, MEASURE)'||
'VALUES('||
pTable||', '||pField||', ('||
'SELECT SUM(CASE WHEN '||pField||' <> 0 THEN 1 END) /COUNT(*) FROM'||
pTable||'));';
EXECUTE IMMEDIATE(v_sql);
COMMIT;
EXCEPTION
...
END;
但是,我一直收到ERROR- ORA-00923:FROM关键字未找到预期的位置。任何帮助表示赞赏。
谢谢
你的解释不是很清楚,我试图用下面的例子/进一步描述来澄清我对它的理解(通过扩展我的想象力)
我们假设您有两个主要表格
create table tbl_1(
id int not null primary_key,
value_1 int
);
create table tbl_2(
id int not null primary_key,
value_2 int
);
如果您将tbl_1,value_1作为参数传递给您的过程,那么您的插入SQL应该是
INSERT INTO TEST_DATA_QTY_AND (TABLE_ID, FLD_ID, MEASURE) values ('tbl_1', 'value_1', (select sum(case when value_1 <> 0 then 1 else 0 end) from tbl_1))
当您将tbl_2,value_2作为参数传递给您的过程时,您的插入SQL应该是
INSERT INTO TEST_DATA_QTY_AND (TABLE_ID, FLD_ID, MEASURE) values ('tbl_2', 'value_2', (select sum(case when value_2 <> 0 then 1 else 0 end) from tbl_2))
如果这种理解是正确的,那么以下应该有效
CREATE OR REPLACE PROCEDURE DATA_QTY_AND(pTable IN VARCHAR2, pField IN VARCHAR2)
IS
v_sql varchar2(2000);
BEGIN
v_sql := utl_lms.format_message(
'INSERT INTO TEST_DATA_QTY_AND (TABLE_ID, FLD_ID, MEASURE) VALUES('''%s''', '''%s''', '
||'(SELECT SUM(CASE WHEN %s <> 0 THEN 1 ELSE 0 END)/ COUNT(*) FROM %s))',
pTable, pField, pField, pTable);
EXECUTE IMMEDIATE(v_sql);
END;
注意我已将事务处理和异常处理作为练习。另请注意,在撰写本文时,我无法访问Oracle DB,因此无法创建/编译以清除任何错误/问题。你应该尝试解决问题(如果有的话)。如果您不能,请发表评论,我将在访问数据库实例时这样做。
但是,所有这些只有在我的问题扩展正确时才会出现。
您需要在文字字符串值周围放置单引号,并且用于包含动态SQL字符串的单引号不计算在内。我们可以尝试使用两个单引号来表示单个文字单引号:
v_sql := 'INSERT INTO TEST_DATA_QTY_AND (TABLE_ID, FLD_ID, MEASURE) ' ||
'VALUES(' ||
'''' || pTable || ''', ''' || pField || ''', (' ||
'SELECT SUM(CASE WHEN ' || pField || ' <> 0 THEN 1 END) / COUNT(*) FROM ' ||
pTable || '))';
请注意,在子查询中,您将pField
(文本变量)与0
进行比较,不带引号,即整数。这没有意义,所以在上面的片段中我与'0'
而不是数字进行比较。
ORA-00923:未找到FROM关键字。
你的字符串看起来像这样:
FROM'||
pTable||'));';
文字FROM
之后没有空格,因此汇编代码将表名参数与FROM连接起来,形成如下字符串:
SEELCT COLUMN_1 FROMTABLE_23
因此错误。
动态SQL很难,因为它将编译错误转变为运行时错误。如果你进行一些调试,你会为自己省去很多悲伤。一个简单的dbms_output.put_line(v_sql);
可以让你看到汇编的代码:你可能会立即发现你的bloomer。
你可以在execute immediate
关键字后面的变量中使用using
create or replace procedure data_qty_and ( pTable varchar2, pField varchar2 ) is
v_sql varchar2(2000);
begin
v_sql := 'insert into test_data_qty_and( table_id, fld_id, measure )
select :1, :2, sum(case when :2 <> 0 then 1 end ) /count(*) from '||pTable;
dbms_output.put_line(v_sql);
execute immediate v_sql using pTable, pField, pField;
commit;
exception when others then dbms_output.put_line(sqlerrm);
end;
使用绑定变量总是比在代码块中易受注入攻击的字符串连接好得多。