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.