sql >> Databasteknik >  >> RDS >> Oracle

Transponera frågeresultat i Oracle 11g

Du är nära - det du vill ha är en kombination av UNPIVOT och PIVOT :

with T AS (
  select 1 as element, 1.1 as reading1, 1.2 as reading2, 1.3 as reading3 from dual union all
  select 2 as element, 2.1 as reading1, 2.2 as reading2, 2.3 as reading3 from dual union all
  select 3 as element, 3.1 as reading1, 3.2 as reading2, 3.3 as reading3 from dual 
)
select * from (
  select * from t
  unpivot (reading_value
    for reading_name in ("READING1", "READING2", "READING3")
    )
  pivot(max(reading_value) for element in (1,2,3)
  )
)
order by reading_name

Den här frågan

  • konverterar kolumnerna läsning1, läsning2, läsning3 i separata rader (namnet går in i läsnamn , värdet i reading_value ); detta ger oss en rad per (element, läsnamn)
  • konverterar raderna 1, 2*, 3 (värdena för element ) i kolumnerna '1', '2', '3'; detta ger oss en rad per läsnamn

UPPDATERA

Om listan med element inte är känd förrän vid körning (t.ex. för att användaren har möjlighet att välja dem), behöver du ett mer dynamiskt tillvägagångssätt. Här är en lösning som dynamiskt skapar en SQL-sats för den givna listan med element och använder en sys_refcursor för resultatuppsättningen.

-- setup table
create table T AS 
  select 1 as element, 1.1 as reading1, 1.2 as reading2, 1.3 as reading3 from dual union all
  select 2 as element, 2.1 as reading1, 2.2 as reading2, 2.3 as reading3 from dual union all
  select 3 as element, 3.1 as reading1, 3.2 as reading2, 3.3 as reading3 from dual ;  
/

declare
  l_Elements dbms_sql.Number_Table;

  function pivot_it(p_Elements in dbms_sql.Number_Table) 
    return sys_refcursor is
      l_SQL CLOB := empty_clob();
      l_Result sys_refcursor;
    begin
      l_SQL := '
        select * from (
          select * from t 
            unpivot (reading_value
              for reading_name in ("READING1", "READING2", "READING3")
            )
          pivot(max(reading_value) for element in (';
      for i in 1 .. p_Elements.count
              loop
                  l_SQL := l_SQL || to_char(p_Elements(i)) || ',';
                end loop;
      -- remove trailing ','                
      l_SQL := regexp_replace(l_SQL, ',$');                
      l_SQL := l_SQL || ')
        )
      )';
      dbms_output.put_line(l_SQL);
      open l_Result for l_SQL;
      return l_Result;
  end;      
begin
  l_Elements(1) := 1;
  l_Elements(2) := 2;
  -- uncomment this line to get all 3 elements
  -- l_Elements(3) := 3;
  -- return the cursor into a bind variable (to be used in the host environment)
  :p_Cursor := pivot_it(l_Elements);  
end;

Hur du använder markören som returneras från den här funktionen beror på miljön du använder - i SQL/Plus kan du bara skriva ut den, och de flesta programmeringsspråkens Oracle-bindningar stöder det direkt.

VARNING: Även om den här koden fungerar för de data som tillhandahålls, saknar den ens grundläggande felkontroll. Detta är särskilt viktigt eftersom dynamisk SQL alltid är ett möjligt mål för SQL-injektionsattacker.




  1. mysql välj endast nästa veckas data

  2. Kan mysql importera en csv eller annan txt-fil till en kolumn?

  3. Docker PGMASTER PostgreSQL versionsuppdatering

  4. XML-fält - Fråga