【问题标题】:Parameter for IN query oracle [duplicate]IN查询oracle的参数[重复]
【发布时间】:2014-02-24 17:23:12
【问题描述】:
SELECT * FROM EMPLOYEE
WHERE EMP_NAME IN (:EMP_NAME);

这是我的查询,现在我想将 EMP_NAME 参数作为字符串列表发送。
当我在 SQL 开发人员中运行此查询时,它被要求发送 EMP_NAME 作为参数,现在我想发送“Kiran”、“Joshi”(基本上,我想获取员工姓名为 Kiran 或 Joshi 的员工的详细信息. 查询执行过程中应该如何传值?

当我单独使用值 Kiran 时它可以工作,但是当我与任何其他字符串连接时它不会工作。这有什么指点吗?

我试过下面的那个
'基兰','乔希'
上述方法不起作用,因为这是一个单一的参数,它会尝试名称为'Kiran',Joshi'的员工,但不会出现。可以理解,但是为了实现这个东西,我要怎么做呢?

任何帮助将不胜感激。

【问题讨论】:

  • 您可以通过创建一个以参数为 EMP_NAME 的函数或过程来尝试。
  • Kedarnath,感谢您的快速回复,但您能帮我指导我如何做到这一点吗?
  • 欢迎您,我已经很久没有使用 PL Sql 部分了。但是你可以谷歌这部分。请记住,这很容易没有那么难:)
  • 这里的重点是我从 Java 层调用这个查询,我想在这种情况下避免 SQL 注入。因此,我采用了参数方法。但是如何在作为动态形成的参数发送时实现这一点?
  • 运行时需要多少个参数?

标签: oracle


【解决方案1】:

感谢帮助我解决这个问题的人。

我可以使用建议的方式得到解决方案,下面是方法

SELECT * FROM EMPLOYEE WHERE EMP_NAME IN (&EMP_NAME)

我已经尝试过这种方式,以下是我测试过的场景,它们运行良好。

场景 1:

要仅获取"Kiran" 的详细信息,则在这种情况下,当sql 开发人员提示时,EMP_NAME 的值为Kiran。它奏效了。

场景 2:

要获取"Kiran""Joshi" 的详细信息,则EMP_NAME 的值发送为

Kiran','Joshi

在这种情况下它也有效。

感谢 Kedarnath 帮助我实现解决方案 :)

【讨论】:

  • 虽然这可能适用于即席查询,但这通常是一个非常糟糕的主意 - 它对 SQL 注入开放(尝试使用 "'Kiran') 或 1=1 --" 作为您的 EMP_NAME 参数) ,并且它给数据库带来了很多不必要的负载,因为您没有使用绑定变量,因此每次执行此查询时,您都会生成一个新的、不同的 SQL 语句并强制执行所谓的“硬解析“由数据库。这根本无法扩展。
  • 同意 Frank Schmitt,基本上我想避免 SQL 注入,因此采用了参数化方法。但是现在由于这也对 SQL 注入开放,因此它不能被称为最佳解决方案。为了避免这种情况,我们现在动态地形成 IN 子句,而不是向单个参数添加动态值。感谢您的建议。我确保我不会以这种方式使用,但这个问题肯定以某种方式帮助了我。
  • 动态形成 IN 子句(即在 Java 中动态构建 SQL 字符串,而不是使用准备好的语句)会遇到同样的问题 - 您的应用程序仍然会受到性能不佳的影响,并且您仍然容易受到攻击到 SQL 注入。唯一明智的方法是对 in 列表中的值使用单独的(临时)表或使用嵌套表,请参阅 OracleUser 的答案。
【解决方案2】:

IN 子句会被隐式转换成多个 OR 条件.. 限制为 1000.. 也就是用绑定变量查询, 执行计划会被重用.. IN 子句支持绑定变量会影响绑定变量的基本用法,因此 oracle 将其限制在语法级别本身。

唯一的方法是像name in (:1,:2) 并绑定其他值..

为此,您可以动态 SQL 在循环中构造 in 子句绑定变量。

另一种方式是调用过程或函数(pl/sql)

DECLARE
    v_mystring VARCHAR(50);
    v_my_ref_cursor sys_refcursor;
    in_string varchar2='''Kiran'',''Joshi''';
    id2 varchar2(10):='123'; --- if some other value you have to compare
        myrecord tablename%rowtype;
  BEGIN

    v_mystring := 'SELECT a.*... from tablename a where name= :id2 and 
                    id in('||in_string||')';

    OPEN v_my_ref_cursor FOR v_mystring USING id2;

    LOOP
      FETCH v_my_ref_cursor INTO myrecord;
      EXIT WHEN v_my_ref_cursor%NOTFOUND;
        ..
      -- your processing
    END LOOP;
    CLOSE v_my_ref_cursor;

  END;

IN 子句最多支持 1000 个项目。您始终可以使用表来代替。该表可能是Global Temporary Table(GTT),其数据对特定会话可见。

您仍然可以使用嵌套表(如 PL/SQL 表)

TABLE() 会将PL/Sql 表转换为 SQL 可理解的表对象(实际上是一个对象)

下面是一个简单的例子。

CREATE TYPE pr AS OBJECT
           (pr  NUMBER);
/
CREATE TYPE prList AS TABLE OF pr;
/

declare
  myPrList prList := prList ();
  cursor lc is 
    select * 
      from (select a.*
              from yourtable a
                   TABLE(CAST(myPrList as prList)) my_list
             where 
                   a.pr = my_list.pr
             order by a.pr desc) ;
  rec lc%ROWTYPE;

BEGIN 
  /*Populate the Nested Table, with whatever collection you have */
  myPrList := prList ( pr(91),
                       pr(80));
  /*
     Sample code: for populating from your TABLE OF NUMBER type 

     FOR I IN 1..your_input_array.COUNT
     LOOP
          myPrList.EXTEND;
          myPrList(I) := pr(your_input_array(I));
     END LOOP;
  */
  open lc;
  loop 
    FETCH lc into rec;
    exit when lc%NOTFOUND; -- Your Exit WHEN condition should be checked afte FETCH iyself!
    dbms_output.put_line(rec.pr);
  end loop;
  close lc;
END;
/

【讨论】:

  • 但我猜这不是一个正常的查询,对吧?我想这是一个功能/过程。是的,我同意使用函数/程序我可以实现这一点,但我想使用一个简单的查询来完成它。那样不行吗?
  • IN 子句将被隐式转换为 OR 条件.. 限制为 1000.. 还使用绑定变量表示查询,执行计划将被重用.. 因此支持 IN 子句的绑定变量将因此影响绑定变量的基本用法,因此 oracle 将其限制在语法级别本身。唯一的方法就像 name in (?1,?2) 并绑定其他值..
  • 我会选择 GTT(临时表)方法 - 易于理解且效果很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
  • 2017-08-19
  • 2021-10-14
相关资源
最近更新 更多