... pivot (somme (A) pour B dans (X))
Maintenant, B est du type de données varchar2 et X est une chaîne de valeurs varchar2 séparées par des virgules.
Les valeurs pour X sont des valeurs sélectionnées distinctes d’une colonne (disons CL) de la même table. De cette façon, la requête pivot fonctionnait.
Mais le problème est que chaque fois qu'il y a une nouvelle valeur dans la colonne CL, je dois l'ajouter manuellement à la chaîne X.
J'ai essayé de remplacer X par certaines valeurs distinctes de CL. Mais la requête n'est pas en cours d'exécution.
Je pensais que c'était dû au fait que, pour remplacer X, nous avons besoin de valeurs séparées par des virgules.
Ensuite, j’ai créé une fonction qui renvoie exactement le résultat à la chaîne X. Mais la requête ne s’exécute toujours pas.
Les messages d'erreur affichés ressemblent à "manquant de parenthèses droites", "canal de communication de fin de fichier", etc.
J'ai essayé pivot xml au lieu de simplement pivot, la requête s'exécute mais donne des vlaues comme oraxxx, etc., qui ne contiennent aucune valeur.
Peut-être que je ne l'utilise pas correctement.
Pouvez-vous me dire une méthode pour créer un pivot avec des valeurs dynamiques?
Vous ne pouvez pas insérer de chaîne non constante dans la clause IN
de la clause pivot.
Vous pouvez utiliser Pivot XML pour cela.
De documentation :
sous-requête Une sous-requête est utilisée uniquement avec le mot-clé XML . Lorsque vous spécifiez une sous-requête, toutes les valeurs trouvées par la sous-requête sont utilisées pour pivoter
Ça devrait ressembler à ça:
select xmlserialize(content t.B_XML) from t_aa
pivot xml(
sum(A) for B in(any)
) t;
Vous pouvez également avoir une sous-requête au lieu du mot clé ANY
:
select xmlserialize(content t.B_XML) from t_aa
pivot xml(
sum(A) for B in (select cl from t_bb)
) t;
Vous ne pouvez pas insérer une instruction dynamique dans l'instruction IN du PIVOT sans utiliser XML PIVOT, qui génère une sortie moins que souhaitable. Cependant, vous pouvez créer une chaîne IN et la saisir dans votre instruction.
Premièrement, voici mon exemple de table;
myNumber myValue myLetter
---------- ---------- --------
1 2 A
1 4 B
2 6 C
2 8 A
2 10 B
3 12 C
3 14 A
Commencez par configurer la chaîne à utiliser dans votre instruction IN. Ici, vous mettez la chaîne dans "str_in_statement". Nous utilisons COLUMN NEW_VALUE et LISTAGG pour configurer la chaîne.
clear columns
COLUMN temp_in_statement new_value str_in_statement
SELECT DISTINCT
LISTAGG('''' || myLetter || ''' AS ' || myLetter,',')
WITHIN GROUP (ORDER BY myLetter) AS temp_in_statement
FROM (SELECT DISTINCT myLetter FROM myTable);
Votre chaîne ressemblera à:
'A' AS A,'B' AS B,'C' AS C
Maintenant, utilisez l'instruction String dans votre requête PIVOT.
SELECT * FROM
(SELECT myNumber, myLetter, myValue FROM myTable)
PIVOT (Sum(myValue) AS val FOR myLetter IN (&str_in_statement));
Voici la sortie:
MYNUMBER A_VAL B_VAL C_VAL
---------- ---------- ---------- ----------
1 2 4
2 8 10 6
3 14 12
Il y a cependant des limites. Vous ne pouvez concaténer qu'une chaîne de 4 000 octets maximum.
Pour les lecteurs ultérieurs, voici une autre solution https://technology.amis.nl/2006/05/24/dynamic-sql-pivoting-stiv-stealing-antons-thunder/
permettant une requête comme
select * from table( pivot( 'select deptno, job, count(*) c from scott.emp group by deptno,job' ) )
UTILISER LA RECHERCHE DYNAMIQUE
Le code de test est ci-dessous
-- DDL for Table TMP_TEST
--------------------------------------------------------
CREATE TABLE "TMP_TEST"
( "NAME" VARCHAR2(20),
"APP" VARCHAR2(20)
);
/
SET DEFINE OFF;
Insert into TMP_TEST (NAME,APP) values ('suhaib','2');
Insert into TMP_TEST (NAME,APP) values ('suhaib','1');
Insert into TMP_TEST (NAME,APP) values ('shahzad','3');
Insert into TMP_TEST (NAME,APP) values ('shahzad','2');
Insert into TMP_TEST (NAME,APP) values ('shahzad','5');
Insert into TMP_TEST (NAME,APP) values ('tariq','1');
Insert into TMP_TEST (NAME,APP) values ('tariq','2');
Insert into TMP_TEST (NAME,APP) values ('tariq','6');
Insert into TMP_TEST (NAME,APP) values ('tariq','4');
/
CREATE TABLE "TMP_TESTAPP"
( "APP" VARCHAR2(20)
);
SET DEFINE OFF;
Insert into TMP_TESTAPP (APP) values ('1');
Insert into TMP_TESTAPP (APP) values ('2');
Insert into TMP_TESTAPP (APP) values ('3');
Insert into TMP_TESTAPP (APP) values ('4');
Insert into TMP_TESTAPP (APP) values ('5');
Insert into TMP_TESTAPP (APP) values ('6');
/
create or replace PROCEDURE temp_test(
pcursor out sys_refcursor,
PRESULT OUT VARCHAR2
)
AS
V_VALUES VARCHAR2(4000);
V_QUERY VARCHAR2(4000);
BEGIN
PRESULT := 'Nothing';
-- concating activities name using comma, replace "'" with "''" because we will use it in dynamic query so "'" can effect query.
SELECT DISTINCT
LISTAGG('''' || REPLACE(APP,'''','''''') || '''',',')
WITHIN GROUP (ORDER BY APP) AS temp_in_statement
INTO V_VALUES
FROM (SELECT DISTINCT APP
FROM TMP_TESTAPP);
-- designing dynamic query
V_QUERY := 'select *
from ( select NAME,APP
from TMP_TEST )
pivot (count(*) for APP in
(' ||V_VALUES|| '))
order by NAME' ;
OPEN PCURSOR
FOR V_QUERY;
PRESULT := 'Success';
Exception
WHEN OTHERS THEN
PRESULT := SQLcode || ' - ' || SQLERRM;
END temp_test;
J'ai utilisé la méthode ci-dessus (fonction personnalisée pivot Anton (PL/SQL) Anton ()) et le travail a été fait! Comme je ne suis pas un développeur Oracle professionnel, voici les étapes simples que j'ai effectuées:
1) Téléchargez le paquet Zip pour y trouver le fichier pivotFun.sql . 2) Exécutez une fois le fichier pivotFun.sql pour créer une nouvelle fonction 3) Utilisez la fonction en SQL normal.
Soyez prudent avec les noms de colonnes dynamiques. Dans mon environnement, le nom de colonne est limité à 30 caractères et ne peut contenir qu'un seul guillemet. Donc, ma requête ressemble maintenant à ceci:
SELECT
*
FROM
table(
pivot('
SELECT DISTINCT
P.proj_id,
REPLACE(substr(T.UDF_TYPE_LABEL, 1, 30), '''''''','','') as Attribute,
CASE
WHEN V.udf_text is null and V.udf_date is null and V.udf_number is NOT null THEN to_char(V.udf_number)
WHEN V.udf_text is null and V.udf_date is NOT null and V.udf_number is null THEN to_char(V.udf_date)
WHEN V.udf_text is NOT null and V.udf_date is null and V.udf_number is null THEN V.udf_text
ELSE NULL END
AS VALUE
FROM
project P
LEFT JOIN UDFVALUE V ON P.proj_id = V.proj_id
LEFT JOIN UDFTYPE T ON V.UDF_TYPE_ID = T.UDF_TYPE_ID
WHERE
P.delete_session_id IS NULL AND
T.TABLE_NAME = ''PROJECT''
')
)
Fonctionne bien avec des enregistrements allant jusqu'à 1 m.
Je ne vais pas répondre exactement à la question posée par OP, je vais simplement décrire comment le pivot dynamique peut être réalisé.
Ici, nous devons utiliser SQL dynamique, en récupérant d'abord les valeurs de colonne dans une variable et en passant la variable à l'intérieur de SQL dynamique.
EXEMPLE
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
Si nécessaire, vous pouvez également créer une table temporaire et effectuer une requête de sélection dans cette table temporaire pour afficher les résultats. C'est simple, il suffit d'ajouter le CREATE TABLE TABLENAME AS
dans le code ci-dessus.
sqlqry :=
'
CREATE TABLE TABLENAME AS
select * from