代码之家  ›  专栏  ›  技术社区  ›  rics

在Oracle中,如何将多行组合成逗号分隔的列表?[复制品]

  •  97
  • rics  · 技术社区  · 15 年前

    我有一个简单的问题:

    select * from countries
    

    结果如下:

    country_name
    ------------
    Albania
    Andorra
    Antigua
    .....
    

    我想在一行中返回结果,如下所示:

    Albania, Andorra, Antigua, ...
    

    当然,我可以编写一个pl/sql函数来完成这个任务(我已经在Oracle10g中做过),但是对于这个任务,是否有更好的、最好是非Oracle特定的解决方案(或者可能是内置的函数)?

    我通常使用它来避免子查询中出现多行,因此,如果一个人拥有不止一个公民身份,我不希望她/他在列表中是重复的。

    我的问题是基于 SQL server 2005 .

    更新 : 我的函数如下:

    CREATE OR REPLACE FUNCTION APPEND_FIELD (sqlstr in varchar2, sep in varchar2 ) return varchar2 is
    ret varchar2(4000) := '';
    TYPE cur_typ IS REF CURSOR;
    rec cur_typ;
    field varchar2(4000);
    begin
         OPEN rec FOR sqlstr;
         LOOP
             FETCH rec INTO field;
             EXIT WHEN rec%NOTFOUND;
             ret := ret || field || sep;
         END LOOP;
         if length(ret) = 0 then
              RETURN '';
         else
              RETURN substr(ret,1,length(ret)-length(sep));
         end if;
    end;
    
    11 回复  |  直到 6 年前
        1
  •  69
  •   Daniel Emge    6 年前

    这里有一个简单的方法,不需要Stragg或创建函数。

    create table countries ( country_name varchar2 (100));
    
    insert into countries values ('Albania');
    
    insert into countries values ('Andorra');
    
    insert into countries values ('Antigua');
    
    
    SELECT SUBSTR (SYS_CONNECT_BY_PATH (country_name , ','), 2) csv
          FROM (SELECT country_name , ROW_NUMBER () OVER (ORDER BY country_name ) rn,
                       COUNT (*) OVER () cnt
                  FROM countries)
         WHERE rn = cnt
    START WITH rn = 1
    CONNECT BY rn = PRIOR rn + 1;
    
    CSV                                                                             
    --------------------------
    Albania,Andorra,Antigua                                                         
    
    1 row selected.
    

    正如其他人提到的,如果您使用的是11g r2或更高版本,那么现在可以使用更简单的listagg。

    select listagg(country_name,', ') within group(order by country_name) csv
      from countries;
    
    CSV                                                                             
    --------------------------
    Albania, Andorra, Antigua
    
    1 row selected.
    
        2
  •  108
  •   schnatterer RealHowTo    10 年前

    这个 WM_CONCAT 函数(如果包含在数据库中,在Oracle 11.2之前)或 LISTAGG (从Oracle11.2开始)应该很好地完成这个技巧。例如,这将获取架构中以逗号分隔的表名列表:

    select listagg(table_name, ', ') within group (order by table_name) 
      from user_tables;
    

    select wm_concat(table_name) 
      from user_tables;
    

    More details/options

    Link to documentation

        3
  •  18
  •   BMaximus    8 年前

    对于Oracle,您可以使用 LISTAGG

        4
  •  16
  •   CassOnMars    11 年前

    您可以尝试此查询。

    select listagg(country_name,',') within group (order by country_name) cnt 
    from countries; 
    
        5
  •  15
  •   Noel    11 年前

    您也可以使用它:

    SELECT RTRIM (
              XMLAGG (XMLELEMENT (e, country_name || ',')).EXTRACT ('//text()'),
              ',')
              country_name
      FROM countries;
    
        6
  •  4
  •   tuinstoel    15 年前

    最快的方法是使用Oracle Collect函数。

    您也可以这样做:

    select *
      2    from (
      3  select deptno,
      4         case when row_number() over (partition by deptno order by ename)=1
      5             then stragg(ename) over
      6                  (partition by deptno
      7                       order by ename
      8                         rows between unbounded preceding
      9                                  and unbounded following)
     10         end enames
     11    from emp
     12         )
     13   where enames is not null
    

    访问该站点,询问Tom并搜索“stragg”或“string concatenation”。许多 例子。还有一个没有文档记录的Oracle功能来满足您的需求。

        7
  •  2
  •   Peter Mortensen user1284631    13 年前

    我需要一个类似的东西,并找到了以下解决方案。

    select RTRIM(XMLAGG(XMLELEMENT(e,country_name || ',')).EXTRACT('//text()'),',') country_name from  
    
        8
  •  2
  •   Emil    12 年前

    在本例中,我们创建了一个函数,将一个逗号分隔的不同行级别AP发票保留原因列表放入一个字段中,以便进行标题级别查询:

     FUNCTION getHoldReasonsByInvoiceId (p_InvoiceId IN NUMBER) RETURN VARCHAR2
    
      IS
    
      v_HoldReasons   VARCHAR2 (1000);
    
      v_Count         NUMBER := 0;
    
      CURSOR v_HoldsCusror (p2_InvoiceId IN NUMBER)
       IS
         SELECT DISTINCT hold_reason
           FROM ap.AP_HOLDS_ALL APH
          WHERE status_flag NOT IN ('R') AND invoice_id = p2_InvoiceId;
    BEGIN
    
      v_HoldReasons := ' ';
    
      FOR rHR IN v_HoldsCusror (p_InvoiceId)
      LOOP
         v_Count := v_COunt + 1;
    
         IF (v_Count = 1)
         THEN
            v_HoldReasons := rHR.hold_reason;
         ELSE
            v_HoldReasons := v_HoldReasons || ', ' || rHR.hold_reason;
         END IF;
      END LOOP;
    
      RETURN v_HoldReasons;
    END; 
    
        9
  •  1
  •   Peter Mortensen user1284631    13 年前

    我总是需要为此编写一些PL/SQL,或者只是将“,”连接到字段并复制到一个编辑器中,然后从给出单行的列表中删除CR。

    也就是说,

    select country_name||', ' country from countries
    

    两边都有点长。

    如果您查看ask-tom,您将看到大量可能的解决方案,但它们都恢复为类型声明和/或pl/sql

    Ask Tom

        10
  •  0
  •   The iOSDev fibnochi    12 年前
    SELECT REPLACE(REPLACE
    ((SELECT     TOP (100) PERCENT country_name + ', ' AS CountryName
    FROM         country_name
    ORDER BY country_name FOR XML PATH('')), 
    '&<CountryName>', ''), '&<CountryName>', '') AS CountryNames
    
        11
  •  -2
  •   chown    13 年前

    您可以使用此查询执行上述任务

    DECLARE @test NVARCHAR(max)
    SELECT @test = COALESCE(@test + ',', '') + field2 FROM #test SELECT field2= @test
    

    有关详细信息和逐步说明,请访问以下链接
    http://oops-solution.blogspot.com/2011/11/sql-server-convert-table-column-data.html