Using IBM DB2 database, I have a three relational tables:
Project: id, title, description
Topic: projectId, value
Tag: projectId, value
I need to produce the following XML file from the previous table:
<projects>
<project id="project1">
<title>title1</title>
<description>desc1</description>
<topic>topic1</topic>
<topic>topic2</topic>
<tag>tag1</tag>
<tag>tag2</tag>
<tag>tag3</tag>
</project>
...
</projects>
I've tried the following query, and it works:
XQUERY
let $projects := db2-fn:sqlquery('SELECT XMLELEMENT(NAME "project", XMLATTRIBUTES(id, title, description)) AS project FROM mydb.Project')
let $TopicSet := db2-fn:sqlquery('SELECT XMLELEMENT(NAME "row", XMLATTRIBUTES(projectId, value)) FROM mydb.Topic')
let $TagSet := db2-fn:sqlquery('SELECT XMLELEMENT(NAME "row", XMLATTRIBUTES(projectId, value)) FROM mydb.Tag')
for $project in $projects return
<project>
{$project/@ID}
<title>{$project/fn:string(@TITLE)}</title>
<description>{$project/fn:string(@DESCRIPTION)}</description>
{for $row in $TopicSet[@PROJECTID=$project/@ID] return <Topic>{$row/fn:string(@VALUE)}</Topic>}
{for $row in $TagSet[@PROJECTID=$project/@ID] return <Tag>{$row/fn:string(@VALUE)}</Tag>}
</project>
;
However, it took 9 hours to complete (there 200k projects in the table)
How can I improve that?
Do I really need to create the three intermediate db2-fn:sqlquery to achieve this? is there another way?
Would it be faster if I create these 3 three intermediate db2-fn:sqlquery and put them in a table (with only one row and one attribute), and then index this before querying the "for $project in $projects return" part?
Or, how would you proceed to achieve my goal?
Best regards,
David
---
As proposed by Peter Schuetze, I tried the XMLAGG as follows:
SELECT
XMLSERIALIZE(
XMLDOCUMENT(
XMLELEMENT(
NAME "Project",
XMLATTRIBUTES(P.project),
XMLAGG(XMLELEMENT(NAME "Topic", Topic.value)),
XMLAGG(XMLELEMENT(NAME "Tag", Tag.value)),
)
) AS CLOB(1M)
)
FROM mydb.project P
LEFT JOIN mydb.Topic Topic ON (P.project = Topic.project)
LEFT JOIN mydb.Tag Tag ON (P.project = Tag.project)
GROUP BY P.project;
This works indeed much much faster!
However, if a project has not any topic, it will still display topic element, with a blank text, such as:
<projects>
<project id="project1">
<title>title1</title>
<description>desc1</description>
<topic></topic>
<tag>tag1</tag>
<tag>tag2</tag>
<tag>tag3</tag>
</project>
...
</projects>
How to remove this "<topic></topic>"?
Répondre
Regardez la fonction XMLAGG. Cela devrait être parfait pour votre besoin. Je ne l'ai pas encore essayé mais l'exemple sur la page liée est presque exactement ce que vous voulez faire.
Utilisation XMLFOREST au lieu de XMLELEMENT s'il y a la possibilité que la colonne pourrait être NULL et vous ne voulez pas une balise d'élément vide lorsque cela se produit. Donc, pour les sujets, vous souhaitez remplacer sa fonction XMLELEMENT avec
XMLFOREST(Topic.value AS "topic")
Il y a un problème avec la façon dont vous avez inclus deux fonctions xmlagg dans la même instruction SELECT. Si vous avez juste un XMLAGG dans votre déclaration, il n'y a pas de problème, puisque le GROUP BY sur la clé parent va s'effondrer soigneusement les entrées de l'enfant qui sont spécifiées dans XMLAGG. Cependant, lorsque vous spécifiez plus d'une fonction XMLAGG dans la même SELECT, la requête produit un produit cartésien en interne, dans ce cas, vous verrez éléments qui se répètent à l'intérieur de chaque groupe retourné par XMLAGG. L'exemple que vous avez donné avec seulement qu'il y ait des zéro ou un des sujets d'un projet ne démontre pas ce problème, mais si un projet avait deux thèmes et trois balises, vous verriez chaque sujet répété trois fois, et chaque étiquette répétée deux fois. Pour éviter cela, vous devez déplacer chaque XMLAGG vers une sous-requête ou une expression de table commune qui produit un seul fragment XML afin que vous puissiez le référencer en toute sécurité à partir de la requête principale.
Voici un exemple qui pousse le XMLAGG vers le bas dans les expressions de table commune. Il supprime également le besoin de XMLFOREST, car XMLAGG ne produira aucun résultat pour un ensemble d'entrées vide.
WITH topicxml(projectid, xmlfragment) AS ( SELECT topic.projectid, XMLAGG(XMLELEMENT(NAME "topic", topic.value) ORDER BY topic.value) FROM mydb.topic topic GROUP BY topic.projectid ), tagxml (projectid, xmlfragment) AS ( SELECT projectid, XMLAGG(XMLELEMENT(NAME "tag", tag.value) ORDER BY tag.value) FROM mydb.tag tag GROUP BY tag.projectid ) SELECT XMLSERIALIZE (CONTENT XMLELEMENT(NAME "project", XMLATTRIBUTES(p.id AS "id"), XMLELEMENT(NAME "title", p.title), XMLELEMENT(NAME "description", p.description), XMLCONCAT(topicxml.xmlfragment, tagxml.xmlfragment) ) AS VARCHAR(2000)) FROM mydb.project p LEFT OUTER JOIN topicxml ON topicxml.projectid = p.id LEFT OUTER JOIN tagxml ON tagxml.projectid = p.id ;
Cette requête va super rapide, et il résout complètement ma question, merci! –
- 1. Données relationnelles au fichier plat
- 2. DB2 Tables relationnelles
- 3. SQL Server 2005, tables relationnelles à xml hiérarchique
- 4. Construire des dépôts pour les tables relationnelles
- 5. Nommer des tables relationnelles sans être ridicule
- 6. Tables de base de données relationnelles
- 7. Comment persuader ascmd.exe de créer des tables en sortie, pas un fichier XML?
- 8. LiNQ imbriqué en XML
- 9. Stockage de données relationnelles en XML
- 10. Documentation de bases de données relationnelles (tables, vues, fonctions, triggers)
- 11. C# Ajouter des données au fichier xml
- 12. Sortie d'exécution au fichier texte
- 13. Charger un fichier XML imbriqué à l'aide de LiNQ
- 14. Comment écrire un fichier XML imbriqué à l'aide de DataSet
- 15. XML Enregistrement imbriqué en C#
- 16. Valeurs de sortie du fichier xml dans un fichier texte au format
- 17. Besoin d'aide avec des applications relationnelles Hibernate
- 18. analyser xml imbriqué en php
- 19. SSIS: du fichier XML à plusieurs tables
- 20. comment accéder au fichier xml?
- 21. Classes de sérialisation en C#. XML imbriqué
- 22. sortie ou écrire dans un fichier xml?
- 23. .NET - Stream DataSet (des données XML) au fichier ZIP?
- 24. Déchiquetage de données XML dans des tables
- 25. Analyser un fichier XML imbriqué avec PHP dans un objet
- 26. Renommage de balises dans la sortie XML
- 27. Insertion rapide des tables de données relationnelles (normalisées) dans la base de données SQL Server 2008
- 28. Modélisation des entités relationnelles Problème
- 29. Sortie XML de l'infopath
- 30. Ecrire des tables Mysql en XML: Problème de sécurité
Merci, ça marche beaucoup plus vite comme ça. Toutefois, des éléments vides apparaissent maintenant lorsqu'il n'y a pas de sujet. (voir la question éditée ci-dessus). Une idée? –