2015-12-10 9 views
5

Ho una domanda:Oracle trasformare tavolo da riga a colonna

select vrec, valnum, valte from val_tb where 
recd in (select recd from rectb where setd = 17) 
AND (vid = 3 OR vid = 26 OR vid = 28); 

Per i risultati di cui sopra, ottengo:

vrec  valnum  valte 
98945823 NULL   Total 
98945823 NULL   06001 
98945823 16.57  NULL 
98945824 NULL   Total 
98945824 NULL   06005 
98945824 0.36   NULL 

voglio trasformarlo per ottenere:

98945823 06001 Total 16.57 
98945824 06005 Total 0.36 

ie combina i risultati con vrec.

È possibile farlo utilizzando Oracle SQL?

+2

@ dang ... ci sono state una serie di domande da voi da ieri.Dovresti impegnarti a risolverli. –

+0

Possibile duplicato di [Come posso ottenere i nomi delle colonne da una tabella in Oracle?] (Http://stackoverflow.com/questions/452464/how-can-i-get-column-names-from-a-table-in -oracolo) –

+3

Principalmente, i progetti di DB inefficienti rendono questo tipo di complessità. –

risposta

6

Un modo per differenziare tra valte valori possono essere controllare se la stringa contiene solo cifre o meno (soluzione povera, ma dovrebbe funzionare):

WITH cte(vrec,valnum, valte) AS 
(
    SELECT 98945823 AS vrec, NULL AS valnum,'Total' AS valte FROM dual 
    UNION ALL SELECT 98945823, NULL, '06001'  FROM dual 
    UNION ALL SELECT 98945823, 16.57, NULL  FROM dual 
    UNION ALL SELECT 98945824, NULL, 'Total'  FROM dual 
    UNION ALL SELECT 98945824, NULL, '06005'  FROM dual 
    UNION ALL SELECT 98945824, 0.36, NULL   FROM dual 
) 
SELECT 
    vrec 
    ,MAX(CASE WHEN REGEXP_LIKE(valte, '^[[:digit:]]*$') THEN valte ELSE NULL END) 
    ,MAX(CASE WHEN NOT REGEXP_LIKE(valte, '^[[:digit:]]*$') THEN valte ELSE NULL END) 
    ,MAX(valnum) 
FROM cte 
GROUP BY vrec; 

SqlFiddleDemo

uscita:

╔═══════════╦═══════════════╦═══════════════╦═════════════╗ 
║ VREC ║ MAX(CASE...) ║ MAX(CASE...) ║ MAX(VALNUM) ║ 
╠═══════════╬═══════════════╬═══════════════╬═════════════╣ 
║ 98945823 ║  06001 ║ Total   ║ 16.57  ║ 
║ 98945824 ║  06005 ║ Total   ║ 0.36  ║ 
╚═══════════╩═══════════════╩═══════════════╩═════════════╝ 

Per la tua cas e lo scambio CTE valori hardcoded con:

select vrec, valnum, valte from val_tb where 
recd in (select recd from rectb where setd = 17) 
AND (vid = 3 OR vid = 26 OR vid = 28); 

tua struttura dei dati è molto povero, quindi questa soluzione è solo soluzione. Dovresti davvero cambiare la struttura sottostante.

0

Hai ragione che questa è la soluzione più semplice ... ma vi siete persi un gruppo:

select vrec, MAX(valnum),'Total' ,MAX(valte) 
    from val_tb 
    where recd in (select recd from rectb where setd = 17) 
    AND (vid = 3 OR vid = 26 OR vid = 28) 
    AND valte <>'Total' --<< Lines with constant 'Total' are of no use... 
GROUP BY vrec; 
0

Ancora un'altra opzione. dati di test afferrò da @ lad2025

WITH cte(vrec,valnum, valte) AS 
(
    SELECT 98945823 AS vrec, NULL AS valnum,'Total' AS valte FROM dual 
    UNION ALL SELECT 98945823, NULL, '06001'  FROM dual 
    UNION ALL SELECT 98945823, 16.57, NULL  FROM dual 
    UNION ALL SELECT 98945824, NULL, 'Total'  FROM dual 
    UNION ALL SELECT 98945824, NULL, '06005'  FROM dual 
    union all select 98945824, 0.36, null   from dual 
) 
select vrec, max(id), max(tot), sum(sum) 
    from 
(
    select vrec, valte  id ,null tot ,null sum from cte where not valte  = 'Total' 
    union all 
    select vrec, null   ,valte ,null from cte where  valte  = 'Total' 
    union all 
    select vrec, null   ,null ,to_char(valnum) from cte where  valnum is not null 
) 
group by vrec 
; 
0
select vrec, 
     max(valte), 
     'Total' || max(valnum) 
from val_tb 
where recd in (select recd from rectb where setd = 17) 
and (vid = 3 OR vid = 26 OR vid = 28) 
and NVL(valte, '#') != 'Total' 
group by vrec; 

Il pensiero alla base di questo è che:

  1. Non ci interessa circa il record con un valte di 'Total'. Possiamo semplicemente anteporre "Totale" allo valte richiesto. Pertanto, escludiamo i record con un valte di "totale", mantenendo i valori NULL, quindi manteniamo il record con uno valnum.
  2. C'è solo un valnum e uno valte che sono NOT NULL per vrec, quindi prendiamo il MAX e GROUP BY il vrec.
0

si può ottenere utilizzando Query pivot come:

WITH pivot_data AS (
      select vrec, valnum, valte from val_tb where 
recd in (select recd from rectb where setd = 17) 
AND (vid = 3 OR vid = 26 OR vid = 28) 
      ) 
    SELECT * 
    FROM pivot_data 
    PIVOT (
       max(valte)  --<-- pivot_clause 
      FOR table --<-- pivot_for_clause 

     IN (FORM Hidden FIELD Name) --<-- pivot_in_clause   
); 

Per dinamica IN clausola, creare una forma nascosta archiviato e passare il seguente risultato della query in questo. Quindi riferisci quel campo alla clausola IN della query precedente.

SELECT LISTAGG(dbms_assert.enquote_literal(valnum), ', ') WITHIN GROUP (ORDER BY valnum) valnum 
FROM (select valnum from val_tb where 
recd in (select recd from rectb where setd = 17) 
AND (vid = 3 OR vid = 26 OR vid = 28) and valnum is not null)