Jesteś blisko — chcesz mieć kombinację UNPIVOT
i 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
To zapytanie
- konwertuje kolumny czytanie1, czytanie2, czytanie3 w osobnych wierszach (nazwa przechodzi w reading_name , wartość do reading_value ); to daje nam jeden wiersz na (element,reading_name)
- konwertuje wiersze 1, 2*, 3 (wartości dla elementu ) w kolumnach „1”, „2”, „3”; to daje nam jeden wiersz na read_name
AKTUALIZUJ
Jeśli lista elementów nie jest znana do czasu uruchomienia (np. dlatego, że użytkownik ma możliwość ich wyboru), potrzebujesz bardziej dynamicznego podejścia. Oto jedno rozwiązanie, które dynamicznie tworzy instrukcję SQL dla podanej listy elementów i używa sys_refcursor
dla zestawu wyników.
-- 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;
Sposób użycia kursora zwróconego przez tę funkcję zależy od używanego środowiska — w SQL/Plus można go po prostu wydrukować, a powiązania Oracle w większości języków programowania obsługują go od razu po zainstalowaniu.
OSTRZEŻENIE: Chociaż ten kod działa dla dostarczonych danych, brakuje w nim nawet podstawowego sprawdzania błędów. Jest to szczególnie ważne, ponieważ dynamiczny SQL jest zawsze możliwym celem ataków typu SQL injection.