用于查询使用的Oracle LISTAGG()

时间:2012-11-06 20:21:15

标签: oracle plsql oracle11g

所以我试图利用 LISTAGG()函数来简单地构建一个逗号分隔列表,以便在底层查询中使用。列表生成工作正常,我只是将输出应用于调试目的,我可以看到我的列表应该是:

  

值:   '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', '纽约', 'ON', '安大略', '或', 'PE', 'QC', '魁北克', '魁北克',“萨斯喀彻温省, 'SK', 'TX', 'VT', 'WA', 'YT'

当我尝试将此列表变量传递给我的查询但是只是为了查看是否会有任何回复,没有任何回复,但是如果我从上面复制/通过省/州列表(按原样)而不是使用“v_Province” “在我的where子句中,我得到了一个结果。我做错了什么?

  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;
  /

2 个答案:

答案 0 :(得分:2)

首先,如果可能的话,在单个陈述中做所有事情几乎总是更有效率。

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

虽然有一个小技巧可以解决这个问题。假设您在两个SELECT语句之间使用字符串,您可以使用regexp_substr()来将字符串变为可用的字符串。

这样的事情会起作用;

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'''才能生效。

这是working example

答案 1 :(得分:1)

您尝试做的事情无法发挥作用,因为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的查询之间进行某种处理,或者可能需要多次使用第一个结果集,那么您应该只使用这种技术。