【问题标题】:Dynamic Insert -- ORA-00923: FROM keyword not found where expected动态插入 -- ORA-00923: FROM 关键字未在预期位置找到
【发布时间】:2019-08-22 11:27:14
【问题描述】:

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

  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 keyword not found where expected。 任何帮助表示赞赏。

谢谢

【问题讨论】:

    标签: sql oracle plsql oracle11g dynamic-sql


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

    但是,只有当我对您的问题的扩展是正确的时,所有这些都是正确的。

    【讨论】:

      【解决方案2】:

      您需要在文字字符串值周围加上单引号,用于包含动态 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 进行比较,即整数。这没有意义,所以在上面的 sn-p 中,我比较的是 '0' 而不是数字。

      【讨论】:

      • pField 指的是 pTable 的一个数值字段
      • 好吧,您的函数签名显示pFieldVARCHAR2,而不是数字。因此,除非您的功能也发生变化,否则我的答案不会改变。
      • pField 是 VARCHAR2,因为它指的是 pTable 给定列的名称(而不是类型)。引用的字段是数字;因此与 0 进行比较。
      【解决方案3】:

      ORA-00923:在预期的地方找不到 FROM 关键字。

      您的字符串如下所示:

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

      FROM 后面没有空格,所以汇编代码会将表名参数与 FROM 连接起来,形成如下字符串:

      SEELCT COLUMN_1 FROMTABLE_23
      

      因此错误。

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

      【讨论】:

        【解决方案4】:

        您可以在using 关键字后使用execute immediate 和变量

        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;
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-15
          • 1970-01-01
          • 2016-10-17
          • 2020-08-03
          相关资源
          最近更新 更多