Vous êtes proche - ce que vous voulez, c'est une combinaison de UNPIVOT
et 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
Cette requête
- convertit les colonnes lecture1, lecture2, lecture3 dans des lignes séparées (le nom va dans reading_name , la valeur dans reading_value ); cela nous donne une ligne par (element,reading_name)
- convertit les lignes 1, 2*, 3 (les valeurs pour element ) dans les colonnes '1', '2', '3' ; cela nous donne une ligne par reading_name
MISE À JOUR
Si la liste des éléments n'est connue qu'au moment de l'exécution (par exemple, parce que l'utilisateur a la possibilité de les sélectionner), vous avez besoin d'une approche plus dynamique. Voici une solution qui crée dynamiquement une instruction SQL pour la liste d'éléments donnée et utilise un sys_refcursor
pour le jeu de résultats.
-- 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;
La façon dont vous utilisez le curseur renvoyé par cette fonction dépend de l'environnement que vous utilisez - dans SQL/Plus, vous pouvez simplement l'imprimer, et les liaisons Oracle de la plupart des langages de programmation le prennent en charge.
AVERTISSEMENT : Bien que ce code fonctionne pour les données fournies, il manque même la vérification des erreurs de base. Ceci est particulièrement important car le SQL dynamique est toujours une cible possible pour les attaques par injection SQL.