动态插入 - ORA-00923:在预期的位置找不到FROM关键字

问题描述 投票:1回答:4

我正在尝试实现一个简单的过程来计算给定字段的不同值的比例,并将结果存储在辅助表中。

  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关键字未找到预期的位置。任何帮助表示赞赏。

谢谢

sql oracle plsql oracle11g dynamic-sql
4个回答
1
投票

你的解释不是很清楚,我试图用下面的例子/进一步描述来澄清我对它的理解(通过扩展我的想象力)

我们假设您有两个主要表格

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,因此无法创建/编译以清除任何错误/问题。你应该尝试解决问题(如果有的话)。如果您不能,请发表评论,我将在访问数据库实例时这样做。

但是,所有这些只有在我的问题扩展正确时才会出现。


1
投票

您需要在文字字符串值周围放置单引号,并且用于包含动态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'而不是数字进行比较。


1
投票

ORA-00923:未找到FROM关键字。

你的字符串看起来像这样:

FROM'||
pTable||'));';

文字FROM之后没有空格,因此汇编代码将表名参数与FROM连接起来,形成如下字符串:

SEELCT COLUMN_1 FROMTABLE_23

因此错误。

动态SQL很难,因为它将编译错误转变为运行时错误。如果你进行一些调试,你会为自己省去很多悲伤。一个简单的dbms_output.put_line(v_sql);可以让你看到汇编的代码:你可能会立即发现你的bloomer。


0
投票

你可以在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;

使用绑定变量总是比在代码块中易受注入攻击的字符串连接好得多。

© www.soinside.com 2019 - 2024. All rights reserved.