Comment obtenir une fonction intégrée pour les valeurs de colonne séparées par des virgules dans sql Dans DB2, par exemple, s'il existe des colonnes avec cet ID de règle et si elle a 3 lignes avec le même identifiant mais trois rôles différents sur 3 rangées, alors récupérer les lignes d'une ligne "3,4,5"
par exemple.
1. 4555 "2"
2. 4555 "3"
3. 4555 "4"
4555 2,3,4
en sortie dans une base de données DB2 sur une ligne
LISTAGGfunction est une nouvelle fonction dans DB2 LUW 9.7
voir exemple:
create table myTable (id int, category int);
insert into myTable values (1, 1);
insert into myTable values (2, 2);
insert into myTable values (5, 1);
insert into myTable values (3, 1);
insert into myTable values (4, 2);
exemple: sélectionne sans ordre dans la colonne groupée
select category, LISTAGG(id, ', ') as ids from myTable group by category;
résultat:
CATEGORY IDS
--------- -----
1 1, 5, 3
2 2, 4
exemple: select with order by dans une colonne groupée
select
category,
LISTAGG(id, ', ') WITHIN GROUP(ORDER BY id ASC) as ids
from myTable
group by category;
résultat:
CATEGORY IDS
--------- -----
1 1, 3, 5
2 2, 4
Je pense qu'avec cette petite requête, vous pouvez faire ce que vous voulez. Cela équivaut à GROUP_CONCAT de MySQL dans DB2.
SELECT
NUM,
SUBSTR(xmlserialize(xmlagg(xmltext(CONCAT( ', ',ROLES))) as VARCHAR(1024)), 3) as ROLES
FROM mytable
GROUP BY NUM;
Cela produira quelque chose comme:
NUM ROLES
---- -------------
1 111, 333, 555
2 222, 444
assumer votre résultat initial était quelque chose comme ça:
NUM ROLES
---- ---------
1 111
2 222
1 333
2 444
1 555
Selon la version de DB2 dont vous disposez, vous pouvez utiliser les fonctions XML pour y parvenir.
Exemple de table avec des données
create table myTable (id int, category int);
insert into myTable values (1, 1);
insert into myTable values (2, 2);
insert into myTable values (3, 1);
insert into myTable values (4, 2);
insert into myTable values (5, 1);
Agréger les résultats à l'aide de fonctions xml
select category,
xmlserialize(XMLAGG(XMLELEMENT(NAME "x", id) ) as varchar(1000)) as ids
from myTable
group by category;
résultats:
CATEGORY IDS
-------- ------------------------
1 <x>1</x><x>3</x><x>5</x>
2 <x>2</x><x>4</x>
Utilisez replace pour améliorer le résultat
select category,
replace(
replace(
replace(
xmlserialize(XMLAGG(XMLELEMENT(NAME "x", id) ) as varchar(1000))
, '</x><x>', ',')
, '<x>', '')
, '</x>', '') as ids
from myTable
group by category;
Résultat nettoyé
CATEGORY IDS
-------- -----
1 1,3,5
2 2,4
Je viens de voir une meilleure solution utilisant XMLTEXT au lieu de XMLELEMENT ici .
Depuis DB2 9.7.5, il existe une fonction pour cela:
LISTAGG(colname, separator)
vérifiez ceci pour plus d'informations: Utilisation de LISTAGG pour transformer des lignes de données en une liste séparée par des virgules
Mon problème était de transposer des champs de ligne (CLOB) en colonne (VARCHAR) avec un fichier CSV et d'utiliser la table transposée pour la génération de rapports. Parce que la transposition sur la couche de rapport ralentit le rapport.
Une solution consiste à utiliser du SQL récursif. Vous pouvez trouver de nombreux articles à ce sujet, mais il est difficile et prend beaucoup de ressources si vous souhaitez joindre toutes vos colonnes transposées récursives.
J'ai créé plusieurs tables temporaires globales dans lesquelles je stockais des colonnes transposées uniques avec un identifiant de clé. Finalement, j'ai eu 6 tables temporaires pour joindre 6 colonnes, mais en raison de l'allocation de ressources limitée, je n'ai pas pu rassembler toutes les colonnes. J'ai opté pour moins de 3 formules puis il me suffisait d'exécuter une requête qui me donnait une sortie en 10 secondes.
J'ai trouvé divers articles sur l'utilisation des fonctions XML2CLOB et j'ai trouvé 3 façons différentes.
REPLACE (VARCHAR (XML2CLOB (XMLAGG (XMLELEMENT (NOM "A"), ALIASNAME.ATTRIBUTENAME)))), '', ',') TRANSPOSED_OUTPUT
NVL (TRIM (',' FROM REPLACE (REMPLACE (REMPLACE (CAST (XML2CLOB)), XMLAGG (XMLELEMENT (NOM "E", ALIASNAME.ATTRIBUTENAME)) AS VARCHAR (100)), '', '' '),' ', ','), '', 'Rien')), 'Rien') comme TRANSPOSED_OUTPUT
RTRIM (REMPLACE (REMPLACE (REMPLACE (VARCHAR (XMLSERIALIZE (XMLAGG (X)) (XMLELEMENT (NOM "A", ALIASNAME.ATTRIBUTENAME) ORDER PAR ALIASNAME.ATTRIBUTENAME), ',', ','), ',' '),' ',' ') AS TRANSPOSED_OUTPUT
Assurez-vous que vous lancez votre "ATTRIBUTENAME" dans varchar dans une sous-requête, puis appelez-le ici.
autre possibilité, avec cte récursive
with tablewithrank as (
select id, category, rownumber() over(partition by category order by id) as rangid , (select count(*) from myTable f2 where f1.category=f2.category) nbidbycategory
from myTable f1
),
cte (id, category, rangid, nbidbycategory, rangconcat) as (
select id, category, rangid, nbidbycategory, cast(id as varchar(500)) from tablewithrank where rangid=1
union all
select f2.id, f2.category, f2.rangid, f2.nbidbycategory, cast(f1.rangconcat as varchar(500)) || ',' || cast(f2.id as varchar(500)) from cte f1 inner join tablewithrank f2 on f1.rangid=f2.rangid -1 and f1.category=f2.category
)
select category, rangconcat as IDS from cte
where rangid=nbidbycategory