Oracle
 sql >> Base de données >  >> RDS >> Oracle

Transposer le résultat de la requête dans Oracle 11g

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.