sql >> Base de Datos >  >> RDS >> Oracle

Transponer el resultado de la consulta en Oracle 11g

Estás cerca:lo que quieres es una combinación de UNPIVOT y 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

Esta consulta

  • convierte las columnas leyendo1, leyendo2, leyendo3 en filas separadas (el nombre va en reading_name , el valor en reading_value ); esto nos da una fila por (elemento, nombre_de_lectura)
  • convierte las filas 1, 2*, 3 (los valores para elemento ) en las columnas '1', '2', '3'; esto nos da una fila por nombre_de_lectura

ACTUALIZAR

Si la lista de elementos no se conoce hasta el momento de la ejecución (por ejemplo, porque el usuario tiene la opción de seleccionarlos), necesita un enfoque más dinámico. Aquí hay una solución que crea dinámicamente una declaración SQL para la lista dada de elementos y usa un sys_refcursor para el conjunto de resultados.

-- 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 forma en que usa el cursor devuelto por esta función depende del entorno que está usando:en SQL/Plus puede simplemente imprimirlo, y la mayoría de los enlaces de Oracle de los lenguajes de programación lo admiten de forma inmediata.

ADVERTENCIA: Si bien este código funciona para los datos proporcionados, carece incluso de una verificación de errores básica. Esto es especialmente importante porque el SQL dinámico siempre es un objetivo posible para los ataques de inyección de SQL.