J'ai la table Oracle 10g suivante appelée _kv:
select * from _kv
ID K V
---- ----- -----
1 name Bob
1 age 30
1 gender male
2 name Susan
2 status married
Je voudrais transformer mes clés en colonnes en utilisant du SQL pur (pas de PL/SQL) afin que la table résultante ressemble à ceci:
ID NAME AGE GENDER STATUS
---- ----- ----- ------ --------
1 Bob 30 male
2 Susan married
K
s uniques dans la table (il n'y en a pas beaucoup)Il existe de nombreux exemples pour savoir quand vous savez comment s'appellent vos colonnes pivotantes, mais je ne trouve pas de solution générique pour Oracle.
Merci!
Oracle 11g fournit une opération PIVOT
qui fait ce que vous voulez.
Solution Oracle 11g
select * from
(select id, k, v from _kv)
pivot(max(v) for k in ('name', 'age', 'gender', 'status')
(Remarque: je n'ai pas de copie de 11g pour le tester, je n'ai donc pas vérifié sa fonctionnalité))}
J'ai obtenu cette solution de: http://orafaq.com/wiki/PIVOT
EDIT - option pivot xml (également Oracle 11g)
Apparemment, il existe également une option pivot xml
pour les cas où vous ne connaissez pas tous les en-têtes de colonnes dont vous pourriez avoir besoin. (voir la section XML TYPE vers le bas de la page située à http://www.Oracle.com/technetwork/articles/sql/11g-pivot-097235.html )
select * from
(select id, k, v from _kv)
pivot xml (max(v)
for k in (any) )
(Remarque: comme auparavant, je n'ai pas de copie de 11g pour le tester, je n'ai donc pas vérifié sa fonctionnalité))
Edit2: Changé v
dans les instructions pivot
et pivot xml
en max(v)
car il est censé être agrégé comme indiqué dans l'un des commentaires. J'ai également ajouté la clause in
qui n'est pas facultative pour pivot
. Bien entendu, le fait de devoir spécifier les valeurs dans la clause in
va à l’encontre de l’objectif consistant à avoir une requête pivot/tableau croisé complètement dynamique, comme le souhaitait l’affiche de cette question.
Pour traiter des situations dans lesquelles il est possible que plusieurs valeurs soient utilisées (v dans votre exemple), j'utilise PIVOT
et LISTAGG
:
SELECT * FROM
(
SELECT id, k, v
FROM _kv
)
PIVOT
(
LISTAGG(v ,',')
WITHIN GROUP (ORDER BY k)
FOR k IN ('name', 'age','gender','status')
)
ORDER BY id;
Puisque vous voulez des valeurs dynamiques, utilisez SQL dynamique et transmettez les valeurs déterminées en exécutant une sélection sur les données de la table avant d'appeler l'instruction pivot.
Arrive pour avoir une tâche sur pivot. Ci-dessous fonctionne pour moi comme testé tout à l'heure sur 11g:
select * from
(
select ID, COUNTRY_NAME, TOTAL_COUNT from ONE_TABLE
)
pivot(
SUM(TOTAL_COUNT) for COUNTRY_NAME in (
'Canada', 'USA', 'Mexico'
)
);
Tout d’abord, il faut analyser de nouveau le pivot dynamique en utilisant pivot xml
. Nous avons un autre moyen de le faire en stockant les noms de colonne dans une variable et en les transmettant dans le SQL dynamique comme ci-dessous.
Considérons que nous avons un tableau comme ci-dessous.
Si nous devons afficher les valeurs de la colonne YR
en tant que noms de colonnes et les valeurs de ces colonnes à partir de QTY
, nous pouvons utiliser le code ci-dessous.
declare
sqlqry clob;
cols clob;
begin
select listagg('''' || YR || ''' as "' || YR || '"', ',') within group (order by YR)
into cols
from (select distinct YR from EMPLOYEE);
sqlqry :=
'
select * from
(
select *
from EMPLOYEE
)
pivot
(
MIN(QTY) for YR in (' || cols || ')
)';
execute immediate sqlqry;
end;
/
RÉSULTAT