Oracle LISTAGG()用于查询使用

Oracle LISTAGG()用于查询使用,oracle,plsql,oracle11g,Oracle,Plsql,Oracle11g,因此,我试图利用listag函数简单地构建一个逗号分隔的列表,以便在基础查询中使用。列表生成工作正常,我只是出于调试目的应用了一个输出,在这里我可以看到我的列表的原样: 价值观: ‘AB’、‘AZ’、‘BC’、‘CA’、‘CT’、‘DC’、‘FL’、‘FO’、‘GA’、‘IL’、‘KS’、‘MA’、‘MB’、‘ME’、‘MN’、‘MS’、‘MT’、‘NB’、‘NC’、‘NL’、‘NOVA’ SCOTIA’、‘NS’、‘NT’、‘NU’、‘NY’、‘ON’、‘安大略’、‘OR’、‘PE’、‘QC’

因此,我试图利用listag函数简单地构建一个逗号分隔的列表,以便在基础查询中使用。列表生成工作正常,我只是出于调试目的应用了一个输出,在这里我可以看到我的列表的原样:

价值观: ‘AB’、‘AZ’、‘BC’、‘CA’、‘CT’、‘DC’、‘FL’、‘FO’、‘GA’、‘IL’、‘KS’、‘MA’、‘MB’、‘ME’、‘MN’、‘MS’、‘MT’、‘NB’、‘NC’、‘NL’、‘NOVA’ SCOTIA’、‘NS’、‘NT’、‘NU’、‘NY’、‘ON’、‘安大略’、‘OR’、‘PE’、‘QC’、‘魁北克’、‘魁北克’、‘萨斯喀彻温’、‘SK’、‘TX’、‘VT’、‘WA’、‘YT’

当我试图将这个列表变量传递给我的查询时,只是为了看看是否会返回任何内容,什么也不会返回,但是如果我按原样从上面复制/通过省/州列表,而不是在where子句中使用v_Province,我会返回一个结果。我做错了什么

  DECLARE
     v_PROVINCE varchar2(500);
     v_results varchar2(1000);
  BEGIn
        dbms_output.enable(1000000);  

       Select '''' || LISTAGG(STATE, ''',''') WITHIN GROUP (ORDER BY STATE) || '''' PROV 
       INTO v_PROVINCE
       from (Select distinct STATE from ADDRDATA where STATE IS NOT NULL);

   DBMS_OUTPUT.PUT_LINE('VALUES: ' || v_PROVINCE);

   Select CITY
   INTO v_results
   from VWPERSONPRIMARYADDRESS
   where state in (v_Province)
   AND ROWNUM <= 1;

   DBMS_OUTPUT.PUT_LINE(v_results);


  END;
  /

您尝试执行的操作将不起作用,因为IN运算符将逗号分隔的列表视为单个值。理论上,您可以将值收集到单个字符串中,然后将字符串解析为单个值,以便下一个查询能够解释它。然而,这将是一个非常糟糕的主意

更好的方法是使用数组将值列表从第一个查询传递到第二个查询:

create type nt_varchar_50 as table of varchar2(10)
/

DECLARE
     v_PROVINCE nt_varchar_50;
     v_results varchar2(1000);
     cursor cur_provinces is
        Select distinct STATE from ADDRDATA where STATE IS NOT NULL;
     i pls_integer;
BEGIN
     dbms_output.enable(1000000); 
     open cur_provinces;
     fetch cur_provinces bulk collect into v_PROVINCE;
     close cur_provinces;

     DBMS_OUTPUT.PUT('VALUES: ');
     for i in v_PROVINCE.first .. v_province.last loop
         if i <> 1 then
            DBMS_OUTPUT.PUT(', ');
         end if;              
         DBMS_OUTPUT.PUT(v_PROVINCE(i));
     end loop;
     DBMS_OUTPUT.PUT_LINE();

     Select CITY
     INTO v_results
     from VWPERSONPRIMARYADDRESS
     where state in (select * from table(v_Province))
     AND ROWNUM <= 1;

     DBMS_OUTPUT.PUT_LINE(v_results);
END;
  /

当然,即使是这样,也比一开始就使用一条SQL语句的效率要低得多。实际上,如果您需要在两个查询之间执行某种不适合SQL的处理,或者可能需要多次使用第一个结果集,则只应使用这种技术。

首先,如果可能的话,在一条语句中执行所有操作几乎总是更有效的

第二个查询不起作用,因为将所有内容返回到单个字符串中。这不是IN语句所需的逗号分隔列表

不过,有一个小技巧可以绕过这个问题。假设您在两个SELECT语句之间使用字符串,您可以使用它将字符串转换为可用的内容

像这样的事情会奏效

select city
  from vwpersonprimaryaddress
 where state in ( 
           select regexp_substr(v_province,'[^'',]+', 1, level) 
             from dual
          connect by regexp_substr(v_province, '[^'',]+', 1, level) is not null
                  )
变量v_province必须更改为引用两次,例如'AB,AZ,BC',才能起作用


这是一张

谢谢!!我知道oracle解释列表值的方式可能有问题,但我不确定为什么。。。我从未使用过regexp_substr函数,但我将进一步探讨它,因为它似乎可以实现这个功能。。。