首页 > 解决方案 > SELECT ...WHERE IN (expressionList) 语句的 expressionList 可以是变量吗?

问题描述

下面的代码创建了一个过滤器,我成功地将它附加到现有的 sql 语句中。

DECLARE V_FILTER VARCHAR2(255);
begin
SELECT DISTINCT 'reserve reporting_unit_code' ||' IN (' || 
                listagg ( chr(39) ||  uic || chr(39) , ',') within group (order by uic) || ')'  
into v_FILTER               
from ( select distinct uicf.uic           
        FROM OWSADHOC.ADHOC_UIC_FILTER UICF
                 INNER JOIN OWSADHOC.ADHOC_USER_ROLE  UROLE
                    ON UICF.ROLE_NAME = UROLE.ROLE_NAME
                 inner join OWSADHOC.ADHOC_USER_DATA uname
                    on uname.USER_ID = UROLE.USER_ID
        WHERE UROLE.ROLE_NAME in (:P_LoggedInUserRoles)  
         and  uname.JASPER_ACCOUNT = :P_LoggedInUserName
         )
      ;   
      DBMS_OUTPUT.PUT_LINE ('GENERATED FILTER: ' || V_FILTER); 
      end;

v_FILTERreserve reporting_unit_code IN ('86749')

P_LoggedInUserRoles当只有一个值时,这很好用。但是,如果我在变量中有一个逗号分隔的列表,它就不起作用。我尝试将expressionList定义为数组。PL/SQL 不使用该方法进行编译。

如果一个有多个值,则表达式列表是否仅限于使用文字值我在任何手册中都找不到该显式语句,但我无法将expressionList定义为作为值集合的变量。

标签: sqloracleplsql

解决方案


不,你不能,但你已经很接近了

逗号分隔的列表将使条件如下所示:

WHERE UROLE.ROLE_NAME in ('Jane, Andrew, Jill')

并返回一个空的结果集。虽然你正在寻找的是

WHERE UROLE.ROLE_NAME in ('Jane', 'Andrew', 'Jill')

很明显,绑定变量的数量必须与一个调用不同,因为列表具有不同的长度。对不起,这不是我们可以轻易做到的。你需要一种叫做动态 SQL 方法 4的东西,这似乎有点矫枉过正。


不过有一个更简单的方法。我们要将逗号分隔值的输入字符串解析为结果集。我们将在子查询中执行此操作,并且可以IN.

这是我们如何做到的

WHERE UROLE.ROLE_NAME in (
  SELECT NAME
  FROM (
    SELECT regexp_substr(:P_LoggedInUserRoles, '(.*?)(,|$)', 1, LEVEL, null, 1) NAME, LEVEL LVL
    FROM   DUAL
    CONNECT BY LEVEL <= regexp_count(:P_LoggedInUserRoles, ',') + 1)
  ORDER BY LVL)

我无耻地从这个问题中偷走了正则表达式:Oracle-Split string comma delimited (string contains spaces and continuous commas) 所以你可能想继续并在那里投票赞成答案。

现在的缺点当然是CONNECT BY即使我们收到一个名字,我们也会一直使用这个技巧,但这是另一个话题。


推荐阅读