Domanda

    

Questa domanda ha già una risposta qui:

         

Ho una semplice query:

select * from countries

con i seguenti risultati:

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

Vorrei restituire i risultati in una riga, quindi in questo modo:

Albania, Andorra, Antigua, ...

Ovviamente, posso scrivere una funzione PL / SQL per fare il lavoro (l'ho già fatto in Oracle 10g), ma esiste una soluzione migliore, preferibilmente non specifica per Oracle (o può essere una funzione integrata) per questo compito?

Vorrei usarlo generalmente per evitare più righe in una sottoquery, quindi se una persona ha più di una cittadinanza, non voglio che sia un duplicato nell'elenco.

La mia domanda si basa sulla domanda simile su SQL server 2005 .

Aggiorna : La mia funzione è simile a questa:

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;
È stato utile?

Soluzione

Ecco un modo semplice senza stravolgere o creare una funzione.

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.

Come altri hanno già detto, se sei su 11g R2 o superiore, ora puoi usare listagg che è molto più semplice.

select listagg(country_name,', ') within group(order by country_name) csv
  from countries;

CSV                                                                             
--------------------------
Albania, Andorra, Antigua

1 row selected.

Altri suggerimenti

La funzione WM_CONCAT (se inclusa nel database, prima di Oracle 11.2) o LISTAGG (che avvia Oracle 11.2) dovrebbe funzionare bene. Ad esempio, viene visualizzato un elenco delimitato da virgole dei nomi delle tabelle nello schema:

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

o

select wm_concat(table_name) 
  from user_tables;

Maggiori dettagli / opzioni

Link alla documentazione

Per Oracle puoi utilizzare LISTAGG

Puoi usare anche questo:

SELECT RTRIM (
          XMLAGG (XMLELEMENT (e, country_name || ',')).EXTRACT ('//text()'),
          ',')
          country_name
  FROM countries;

puoi provare questa query.

select listagg(country_name,',') within group (order by country_name) cnt 
from countries; 

Il modo più veloce è usare la funzione di raccolta Oracle.

Puoi anche farlo:

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

Visita il sito chiedi a tom e cerca "stragg" o "concatenazione di stringhe". Molti esempi. C'è anche una funzione oracolo non documentata per soddisfare le tue esigenze.

Avevo bisogno di qualcosa di simile e ho trovato la seguente soluzione.

select RTRIM(XMLAGG(XMLELEMENT(e,country_name || ',')).EXTRACT('//text()'),',') country_name from  

In questo esempio stiamo creando una funzione per portare un elenco delimitato da virgole di motivi distinti per la conservazione della fattura AP a livello di linea in un campo per la query a livello di intestazione:

 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; 

Ho sempre dovuto scrivere un po 'di PL / SQL per questo o ho semplicemente concatenato un', 'sul campo e copiato in un editor e rimosso il CR dalla lista dandomi la riga singola.

Cioè,

select country_name||', ' country from countries

Un po 'lungo e tortuoso in entrambe le direzioni.

Se guardi Chiedi a Tom vedrai un sacco di possibili soluzioni, ma tutte torneranno a digitare dichiarazioni e / o PL / SQL

Chiedi a Tom

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

è possibile utilizzare questa query per eseguire l'attività sopra

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

per i dettagli e la spiegazione dettagliata visitare il seguente link
http: //oops-solution.blogspot .com / 2011/11 / sql-server-convert-table-column-data.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top