Contamos con la contestación a esta obstáculo, o por lo menos eso deseamos. Si tienes alguna duda dínoslo, que sin dudarlo te responderemos
Solución:
Hay algunas formas de realizar esta transformación de datos. Tienes acceso a la PIVOT
entonces esa será la más fácil, pero si no, entonces puede usar una función agregada y una CASE
.
Versión agregada/caso:
select personid,
max(case when optionid = 'A' then 1 else 0 end) OptionA,
max(case when optionid = 'B' then 1 else 0 end) OptionB,
max(case when optionid = 'C' then 1 else 0 end) OptionC
from PersonOptions
group by personid
order by personid;
Ver SQL Fiddle con demostración
Pivote estático:
select *
from
(
select personid, optionid
from PersonOptions
) src
pivot
(
count(optionid)
for optionid in ('A' as OptionA, 'B' OptionB, 'C' OptionC)
) piv
order by personid
Ver SQL Fiddle con demostración
Versión dinámica:
Las dos versiones anteriores funcionan muy bien si tiene una cantidad conocida de valores, pero si sus valores son desconocidos, querrá implementar sql dinámico y en Oracle puede usar un procedimiento:
CREATE OR REPLACE procedure dynamic_pivot_po(p_cursor in out sys_refcursor)
as
sql_query varchar2(1000) := 'select personid ';
begin
for x in (select distinct OptionID from PersonOptions order by 1)
loop
sql_query := sql_query ||
' , min(case when OptionID = '''||x.OptionID||''' then 1 else null end) as Option_'||x.OptionID;
dbms_output.put_line(sql_query);
end loop;
sql_query := sql_query || ' from PersonOptions group by personid order by personid';
dbms_output.put_line(sql_query);
open p_cursor for sql_query;
end;
/
Luego devuelves los resultados, usarás:
variable x refcursor
exec dynamic_pivot_po(:x)
print x
Los resultados son los mismos con todas las versiones:
| PERSONID | OPTIONA | OPTIONB | OPTIONC |
------------------------------------------
| 1 | 1 | 1 | 0 |
| 2 | 0 | 0 | 1 |
| 3 | 0 | 1 | 0 |
| 4 | 1 | 0 | 1 |
Este sería el equivalente en la sintaxis de SQL Server. Según mi lectura de los documentos de Oracle, NULLIF y PIVOT parecen tener el mismo formato que sus parientes de SQL Server. El desafío será la lista dinámica que debe ser static a menos que haga que la consulta sea dinámica como lo demuestra Itzik, pero no tengo idea de si eso se puede traducir a P/SQL
WITH PersonOptions(PersonID, OptionId) AS
(
SELECT 1, 'A'
UNION ALL SELECT 1, 'B'
UNION ALL SELECT 2, 'C'
UNION ALL SELECT 3, 'B'
UNION ALL SELECT 4, 'A'
UNION ALL SELECT 4, 'C'
)
SELECT
P.PersonId
, NULLIF(P.A, 0) AS OptionA
, NULLIF(P.B, 0) AS OptionB
, NULLIF(P.C, 0) AS OptionC
FROM
PersonOptions PO
PIVOT
(
COUNT(PO.OptionId)
FOR OPtionId IN (A, B, C)
) P;
Prefiero pivotar la consulta manualmente, pero puede usar PIVOT
también.
SELECT PersonID,
MAX(CASE WHEN OptionId ='A' THEN 1 END) AS OptionA,
MAX(CASE WHEN OptionId ='B' THEN 1 END) AS OptionB,
MAX(CASE WHEN OptionId ='C' THEN 1 END) AS OptionC
FROM PersonOptions
GROUP BY PersonID