Chapitre 7. Requêtes XQuery.
Dans cette partie consacrée aux requêtes XQuery, qui
devront fournir des résultats ABC, nous nous proposons de
présenter notre travail de façon graduelle.
Nous débuterons par une requête
élémentaire et tenterons de terminer en fin de chapitre par une
requête fournissant un résultat ABC.
Nous utiliserons des requêtes de type FLWOR.
Produire une liste de clients.
Une première requête simple consiste à
produire la liste des clients.
for $client in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")/ABC/client
return
<p>{($client/@nom)}</p>
|
Dans la première ligne, nous déclarons la variable
« client » en la faisant précéder par le signe $, soit
« $client ».
La variable « $client » est
précédée de la clause FOR.
FOR lance une itération qui permet à la
requête FLWOR de multiples évaluations (récursives). La
fonction « doc » ouvre le document sur lequel portera la
requête.
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")/ABC/client
Pour accéder au document, il est fait usage d'une «
path expression ».
Une « path expression » permet de sélectionner
les éléments ou attributs nécessaires.
Le point de départ en est l'élément root du
file system « / », puis le répertoire « home », puis
le répertoire « jean », puis le répertoire «
Mémoire_ulb_2009 », puis le répertoire « group_21juin
» et enfin le fichier « abc_avril27jn_id01.xml », puis la racine
« / ABC » du fichier, puis la séquence « client
».
Nous lions la variable $client au premier élément
de la séquence « client » dont le « context node »
est « ABC ».
La boucle induite par FOR évaluera chacune des valeurs
prises par chacun des éléments de la séquence «
client ».
La clause « return » envoie un élément
d'information à chaque itération de la requête. Le
résultat demandé est la valeur prise par l'attribut « nom
» de l'élément « client ». A chaque
évaluation, « return » enverra le nom d'un client.
Les évaluations itératives de « for »
cesseront lorsqu'aura été évalué le dernier
élément « client ».
<p>{($client/@nom)}</p>
Nous utilisons un « constructor » XML, afin de
créer un élément <p/>, et donc un résultat de
requête sous forme XML.
Le résultat en est le suivant:
<?xml version="1.0" encoding="UTF-8"?> <p
nom="jaeger"/>
<p nom="cairelli"/>
<p nom="communication"/>
|
Chaque instanciation du résultat est un
élément <p/>.
Nous pouvons modifier cette requête de façon
à obtenir un arbre XML, comportant donc un élément racine,
et des éléments <p> ne contenant que la valeur de
l'attribut « nom ».
Nous choisissons de nommer l'élément racine
<requete/>.
L'entièreté de la requête est
incorporée dans les balises <requete> </requete>
<requete>
{
for $client in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")/ABC/client
return
<p>{data($client/@nom)}</p>
} </requete>
|
Afin de ne conserver que la valeur atomique de l'attribut, nous
faisons appel à la fonction « data » qui permet d'extraire les
valeurs atomiques d'éléments et attributs.
<p>{data($client/@nom)}</p>
Le résultat est un arbre XML comportant
l'élément racine « requête » parent de trois
éléments <p/>. Notons que seuls les noms des trois clients
apparaissent.
<?xml version="1.0" encoding="UTF-8"?> <requete>
<p>jaeger</p>
<p>cairelli</p>
<p>communication</p>
</requete>
|
Nous utiliserons les « constructors » XML pour toutes
les requêtes suivantes.
Les liens.
Nous devons pouvoir établir des liens entre
éléments du document XML, liens équivalents à ceux
définis dans les représentations par modèle
hiérarchique ou ERD.
But de la requête: afficher pour chaque «
activite » les « familles_cout » qui la composent.
<requete_lien>
{
for $in in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")/ABC
for $akty in $in/activite
return
<activite>
<nom_activite>{data($akty/@nom_activite)}</nom_activite>
{
for $famy in
$in/famille_cout[@id_famille_cout=$akty/composition_activite/@id_famille_kout]
return
<famille_cout>
{data($famy/@nom_famille)}</famille_cout>
} </activite>
} </requete_lien>
|
Un lien est à établir entre les «
éléments » « activite » et « famille »,
par comparaison des attributs communs à « activite » et «
famille ».
Pour l'élément « activite », il s'agit de
l'attribut « id_famille_kout » (dans le « path » «
ABC/ activite/composition _activite »).
Pour l'élément « famille cout », il
s'agit de l'attribut « id_famille_cout » (dans le « path »
« ABC/ famille_cout ».
Les valeurs que prennent ces attributs sont: « fam »1,
« fam2 », « fam3 », « fam4 », « fam5 »,
« fam6 », « fam7 » et « fam8 ».
L'évaluation s'opérera en comparant un attribut
« fam1 » trouvé dans un élément « activite
» aux attributs « fam... » des éléments «
famille_cout »; lorsque l'attribut « fam1 » sera trouvé
en
« famille_cout », la valeur de l'attribut «
nom_famille » de cet élément « famille_cout » sera
affichée.
Pour l'élément « activite » dont
l'attribut « id_activite » = "act1", les familles de coût
figurant dans l'élément « composition_activite »
correspondant aux valeurs prises par l'attribut « id_famille _kout »
sont: « fam1 » et « fam2 ».
Le résultat affiché pour cet élément
devrait être « fam1_publicite » et « fam2_bureau ».
D'autres résultats seront affichés: nous ne filtrons pas
Que fait la requête?
La première boucle FOR évalue à partir du
« context node » ABC le premier élément de la
séquence « activite » et le lie à la variable «
$akty ».
La clause « return » en restitue la valeur de
l'attribut « nom_activite ».
Puis, la boucle FOR contenue dans « return »
sélectionne à partir du « context node » « ABC
», le premier élément de la séquence «
famille_cout » et le lie à la variable « $famy » si la
condition suivante est respectée.
La valeur de l'attribut « id_famille_cout » (de
l'élément « famille_cout » traîté) est
comparée à celle prise par l'attribut « id_famille_kout
» du premier élément « composition_activite » de
l'élément
« activite » lié à la variable «
$akty ».
Lorsque la comparaison est positive, la valeur de l'attribut
« nom_famille » de l'élément « famille_cout »
est affichée.
La même itération se reproduit pour la «
composition_activite » suivante de la variable « $akty », et ce
jusqu'à la dernière « composition_activite» de l'
« activite » traitée.
Ensuite, retour à la première boucle FOR, qui
reproduit les mêmes itérations pour le second
élément de la séquence « activite », et ce
jusqu'à ce qu'il n'y ait plus d'élément non traité
dans la séquence
« activite ».
Le résultat figure ci-dessous.
<?xml version="1.0" encoding="UTF-8"?>
<requete_lien>
<activite>
<nom_activite>act1_communication</nom_activite>
<famille_cout>fam1_publicite</famille_cout>
<famille_cout>fam2_bureau</famille_cout>
</activite>
<activite>
<nom_activite>act2_demarchage</nom_activite>
<famille_cout>fam2_bureau</famille_cout>
<famille_cout>fam4_formation_documentation</famille_cout>
</activite>
<activite>
<nom_activite>act3_logistique</nom_activite>
<famille_cout>fam3_stock</famille_cout>
<famille_cout>fam7_outil_production</famille_cout>
</activite> <activite>
<nom_activite>act4_transport</nom_activite>
<famille_cout>fam6_transport</famille_cout>
</activite>
<activite>
<nom_activite>act5_production</nom_activite>
<famille_cout>fam4_formation_documentation</famille_cout>
<famille_cout>fam7_outil_production</famille_cout>
</activite>
<activite>
<nom_activite>act6_comptabilite_abc</nom_activite>
<famille_cout>fam2_bureau</famille_cout>
<famille_cout>fam4_formation_documentation</famille_cout>
<famille_cout>fam5_honoraires</famille_cout>
</activite> <activite>
<nom_activite>act7_telecom</nom_activite>
<famille_cout>fam8_telecom</famille_cout>
</activite> </requete_lien>
|
Notons que nous obtenons un arbre XML ayant pour
élément racine </requete_lien>, qui a pour
éléments enfants les éléments </activite>
lesquels contiennent les éléments </nom_activite> et
</famille_cout>.
Effectuer des opérations arithmétiques.
Nous devons effectuer, pour obtenir des résultats ABC, des
opérations de calcul. Ce sont des opérations
élémentaires, sommer, multiplier et diviser.
- Sommer fait usage de la fonction « SUM », qui est une
fonction d'agrégation portant sur une séquence de
résultats.
- La multiplication est liée à l'opérateur
« * »
- La division a pour opérateurs « div » et
« idiv ». Nous utiliserons « div ».
Sommer les charges .
Cette requête devrait nous retourner la somme des «
montant_htva_total ». Nous reproduisons le fragment de document XML
ci-dessous.
<charge_indirecte id_chargeindirecte="fact001"
montant_htva_total="2000">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact005"
montant_htva_total="2401">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact011"
montant_htva_total="710">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact015"
montant_htva_total="623.85">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact016"
montant_htva_total="310">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact028"
montant_htva_total="4562">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact031"
montant_htva_total="2100">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact032"
montant_htva_total="2542">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact054"
montant_htva_total="600">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact055"
montant_htva_total="240">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact056"
montant_htva_total="211">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact062"
montant_htva_total="118.7">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact071"
montant_htva_total="560">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact072"
montant_htva_total="422">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact075"
montant_htva_total="58">
... </charge_indirecte>
<charge_indirecte id_chargeindirecte="fact100"
montant_htva_total="74.6">
... </charge_indirecte>
|
La requête:
<requete_somme>
{
for $chargeind in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")
//charge_indirecte
return
<Eur> {sum($chargeind/@montant_htva_total)} </Eur>
} </requete_somme>
|
Cette requête comporte une erreur.
Nous la présentons car le résultat, qui n'est pas
celui attendu, illustre très bien la notion de séquence de
résultats.
Fonctionnement de la requête.
La variable « $chargeind » est liée à la
séquence « charge_indirecte ».
Une boucle FOR parcourt une à une les instantiations de
la séquence et les passe à « $chargeind » . Return
affiche à chaque itération l'attribut «
charge_indirecte/@montant_htva_total » de la variable « $chargeind
».
Le résultat retourné.
<?xml version="1.0" encoding="UTF-8"?>
<requete_somme> <Eur>2000</Eur>
<Eur>2401</Eur> <Eur>710</Eur>
<Eur>623.85</Eur> <Eur>310</Eur>
<Eur>4562</Eur> <Eur>2100</Eur>
<Eur>2542</Eur> <Eur>600</Eur>
<Eur>240</Eur> <Eur>211</Eur>
<Eur>118.7</Eur> <Eur>560</Eur>
<Eur>422</Eur> <Eur>58</Eur>
<Eur>74.6</Eur>
</requete_somme>
|
Nous constatons que le résultat n'est pas un total, mais
une séquence des nombres qui auraient du être sommés.
La cause en est que nous avons intégré la fonction
« SUM » dans la séquence de génération de
nombres, alors que la séquence aurait dû se produire dans «
SUM », « SUM » étant une fonction d'agrégation.
Si nous avions appelé la fonction « data » au
lieu de la fonction « SUM », le résultat aurait
été identique.
La requête doit être modifiée de façon
à ce que les itérations FOR se produisent au sein de « SUM
».
Nous invoquons dès lors « SUM » au début
de la requête
<requete_somme>
{ sum(
for $chargeind in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")
//charge_indirecte
return
<Eur> {data($chargeind/@montant_htva_total)}
</Eur>
) } </requete_somme>
|
Nous obtenons le résultat attendu: la somme est de
17533,15 (Euro).
<?xml version="1.0" encoding="UTF-8"?>
<requete_somme>17533.15</requete_somme>
|
Calculer le coût d'une unité d'oeuvre
(d'activité).
Dans cette nouvelle requête, nous voulons calculer le
coût d'une unité d'oeuvre pour une activité
déterminée.
Nous choisissons l'activité5, « act5_production
».
La démarche suivie.
1) Calculer le coût total de l'activité choisie.
- Filtrer les éléments « activite ».
- Les lier aux éléments « famille_cout
».
- Lier les éléments « famille_cout » aux
éléments « charge_indirecte/imputation ».
2) Sommer la quantité de mesurages correspondant à
l'activité choisie.
3) Calculer et sommer.
Le calcul de notre requête peut se résumer par:
SUM « montant_htva_impute » * « proportion_cf
» * « proportion » div SUM « quantite » (de
mesurages).
La requête se présente comme suit:
<requete_calcul_unite_oeuvre>
{
sum(
for $in in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")/ABC,
$akty in $in/activite[@id_activite="act5"],
$compoakt in $akty/composition_activite,
$famy in
$in/famille_cout[@id_famille_cout=$compoakt/@id_famille_kout]/composition_famille,
$pcmn in
$in/charge_indirecte/imputation[@id_pcmn_imputation=$famy/@id_pcmn_fam]
|
return <activite>{data($pcmn/@montant_htva_impute
*$famy/@proportion_cf
*$compoakt/@proportion
div
sum(
for $mesur in
$in/client/commande/mesurage[@id_aktivite="act5"]
return <div>{data($mesur/@quantite)}</div>)
)}
</activite>
)}
</requete_calcul_unite_oeuvre>
|
Fonctionnement de la requête.
Nous utilisons des boucles FOR; notre point de départ sera
le « context node » ABC.
La variable « $akty » est liée au premier
élément de la séquence « activite » qui est
sélectionné si le prédicat « id_activite » =
« act5 » est respecté.
Si le prédicat n'est pas respecté, par
itération le second élément est examiné, le
troisième, jusqu'au dernier si nécessaire.
La variable « $compoact » est liée au premier
élément de la séquence « composition_activite »
dont le « context node » est $akty (qui respecte « act5
»).
La variable « $famy » est liée au premier
élément de la séquence « famille_cout » si un
lien est établi.
Nous établissons un lien avec l'élément
« activite » par comparaison des valeurs des attributs «
famille_cout/@id_famille_cout » et «
activite/composition_activite/@id_famille_kout ».
Le lien est établi si il y a concordance, sinon, il y a
itération vers le second élément de la séquence
« famille_cout », évaluation pour lien, et ce jusqu'au dernier
si nécessaire.
La variable « $pcmn » accède au premier
élément « imputation » du « context node »
« charge _indirecte » .
Comme ci-dessus, un lien est établi avec la variable
« $famy » par comparaison des valeurs des attributs «
id_pcmn_imputation » à « id_pcmn_fam ».
Une itération se produit pour le second
élément « imputation » , etc, tant qu'un lien n'a pas
été établi.
Return reçoit la valeur de l'attribut «
montant_htva_impute » lorsqu'un lien est établi ($pcmn) et traite
le premier résultat en le multipliant par la valeur de l'attribut «
$famy/@proportion_cf » multiplié par la valeur de l'attribut «
$compoakt/@proportion ».
<activite>{data($pcmn/@montant_htva_impute
*$famy/@proportion_cf
*$compoakt/@proportion
|
Nous devons diviser ce résultat par la somme des
quantités de mesurages correspondant. Return comprend une boucle FOR.
La variable « $mesur » est liée aux
éléments de la séquence « mesurage » du «
context node »
« commande », dont la valeur de l'attribut «
id_aktivite » respecte le prédicat « id_aktivite » =
« act5 ».
Cette boucle se produit à l'intérieur d'un «
SUM » qui somme les valeurs prises par l'attribut « quantite »
qui sont retournées.
div
sum(
for $mesur in $in/cient/commande/mesurage[@id_aktivite="act5"]
return
<div>{data($mesur/@quantite)}</div>)
|
Le premier résultat « montant_htva_impute » *
« proportion_cf » * « proportion » est ainsi divisé
par la somme des « quantite ».
Après cette opération, la boucle retourne parcourir
et comparer les éléments « imputation », puis retourne
vers les éléments « composition_famille », et enfin
retourne vers les éléments
« composition_activite » jusqu'à
l'épuisement des éléments « activite ».
Après le dernier « return », la séquence
de résultats est sommée. Le résultat de la
requête:
<?xml version="1.0" encoding="UTF-8"?>
<requete_calcul_unite_oeuvre>18.17860066006601</requete_calcul_unite_oeuvre>
|
Soit 18,178 (Euro) le coût d'une unité d'oeuvre de
l'activité « act5_production ».
Nous avons voulu vérifier au moyen d'un tableur (sous
Linux).
Nous y avons rapporté les données
rencontrées par la requête qui parcours le fichier XML.
mes004
|
8
|
fam4
|
0,34
|
612300
|
1
|
157,85
|
53,67
|
0,71
|
mes008
|
8,5
|
fam4
|
0,34
|
612300
|
1
|
560
|
190,4
|
2,51
|
mes010
|
6
|
fam7
|
0,73
|
601300
|
1
|
850
|
620,5
|
8,19
|
mes012
|
10
|
fam7
|
0,73
|
611130
|
1
|
422
|
308,06
|
4,07
|
mes023
|
2
|
fam7
|
0,73
|
613540
|
1
|
|
0
|
0
|
mes018
|
8
|
fam7
|
0,73
|
630220
|
0,8
|
350
|
204,4
|
2,7
|
mes020
|
7,25
|
|
|
|
|
|
|
|
mes026
|
10
|
|
|
|
|
|
|
|
mes031
|
7
|
|
|
|
|
|
|
|
mes033
|
9
|
|
|
|
|
|
|
|
|
|
|
|
Valeur de 1 unité d'oeuvre de l'activité5
18,18
|
|
75,75
|
|
|
|
|
|
|
|
Les mesurages portant sur l'activité5 sont au total de
75,75 unités.
L'activité 5 est composée des familles fam4 qui
intervient à 34% et fam5 qui intervient à 73%. La famille4 est
constituée du poste pcmn 612300 qui intervient à 100% dans la
famille4.
Nous trouvons dans charge_indirecte/imputation deux «
montants_htva_impute », soit 157,85 (Euro) et 560 (Euro).
157,85 * 1 * 0,34 = 53,67 (Euro) 560 * 1 * 0,34 = 190,4 (Euro)
Le même raisonnement est à appliquer à la
famille7.
Détaillons la dernière ligne: le poste pcmn 630220
qui constitue la famille7: le montant de 350 (Euro) est imputé; il est
multiplié par 80% (intervention dans la famille) et est à nouveau
multiplié par 73%, intervention de la famille dans l'activité5,
soit 350 * 0,73 * 0,8 = 204,4 (Euro)
Chacun de ces produits sont divisés un à un par le
total des unités mesurées, soit 75,75 .
Pour la première ligne: 53,67 / 75,75 = 0,71 (Euro)
...
La dernière ligne: 204,4 /75,75 = 2,7 (Euro)
La somme de ces quotients est bel et bien de 18,18 (Euro) ,
résultat fourni par la requête.
Ayant pu vérifier la justesse du résultat de la
requête, nous calculons encore le coût d'une unité d'oeuvre
de l'activité « act4_transport », et en retenons la valeur
pour la suite: 2,652 (Euro).
<?xml version="1.0" encoding="UTF-8"?>
<requete_calcul_unite_oeuvre>2.6521739130434785</requete_calcul_unite_oeuvre>
Calculer le coût indirect d'une commande
déterminée.
Nous souhaitons obtenir le coût indirect pour une commande
précise.
La démarche suivie.
Nous réutilisons la démarche
précédente, mais le point de départ est une commande
choisie.
1) Sélectionner une commande et calculer le coût
total des activités utilisées. - Filtrer les
éléments « commande ».
- Sélectionner les éléments « activite
» utilisés par la commande choisie. - Les lier aux
éléments « famille_cout ».
- Lier les éléments « famille_cout » aux
éléments « charge_indirecte/imputation ».
2) Sommer la quantité de mesurages correspondant aux
activités traitées.
3) Calculer et sommer.
En cours d'élaboration de cette requête, est apparue
une erreur du fait de la nature différente des activités, erreur
que nous détaillons.
Prenons comme exemple la commande ayant le « id_commande
» com003.
Cette commande comporte deux mesurages, l'un concernant
l'activité « id_aktivite » = « act4 »,
l'autre, l'activité « id_aktivite » = «
act5 ».
Les unités d'oeuvre utilisées pour ces deux
activités sont fondamentalement différentes. l'activité4
transport a pour unité de mesure le kilomètre parcouru.
L'activité5 se mesure elle en heure de production.
Ce tableau synthétise l'information telle qu'elle sera
traitée par la requête.
Nous imaginons qu'activité4 (act4) et activité5
(act5) ont respectivement un coût de 600 (Euro) et 1000 (Euro).
La colonne « produit » doit son appellation au fait
qu'il s'agit du résultat de l'opération: « montant_htva
_impute » * « proportion_cf » * « proportion ».
Du fait de la nature différente des unités
d'oeuvre, nous aurons beaucoup plus de kilomètres que d'heures
prestées.
Nous avons 107 kilomètres (45 + 62) parcourus pour 13
heures de travail (6 + 7).
La requête sommera 120 unités mesurées, sans
distinction quant à leur différence de nature.
Le calcul qui sera effectué pour calculer le coût
d'une unité d'oeuvre sera: 600 (Euro) / 120 et 1000 (Euro) / 120, soit 5
(Euro) et 8,33 (Euro).
Ce qui est évidement faux.
L'opération à effectuer est de diviser
l'activité4 par la somme d'unités s'y rapportant, et pratiquer de
même pour l'activité5.
Pour l'activité4, 600 (Euro) / 107 = 5,61 (Euro) par
unité d'oeuvre
Pour l'activité5, 1000 (Euro) / 13 = 76,92 (Euro) par
unité d'oeuvre
La requête devra donc intégrer la possibilité
de distinguer les différents types d'unité d'oeuvre possibles.
Calculer le coût indirect de la commande « com003
».
Nous traiterons l'exemple qui consiste à afficher le
coût indirect de la commande dont la valeur de « id_commande »
est « com003 ».
Nous reproduisons le fragment du document XML ci-dessous.
<commande id_commande="com003" descriptif="seconde commande"
chiffre_affaire="1852">
<mesurage id_mesurage="mes022" id_aktivite="act4" date="12
avril 2009" quantite="42" unite_oeuvre="kilometre"/>
<mesurage id_mesurage="mes023" id_aktivite="act5" date="12
avril 2009" quantite="2" unite_oeuvre="heure_production"/>
<charge_directe id_charge_d="fact0041" id_pcmn="601000"
montant_dir_htva_impute="640" quantite="1"/>
<charge_directe id_charge_d="fact9999" id_pcmn="620000"
montant_dir_htva_impute="25"
quantite="2"/>
</commande>
|
Nous utilisons comme base la requête
précédente de calcul d'une unité d'oeuvre pour une
activité donnée.
Nous y avons ajouté le prédicat nécessaire
à parcourir le document XML à partir de la commande « com003
» .
La requête se présente comme suit.
<cout_indirect_commande>
{
sum(
for $in in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")//ABC,
$commande in $in/client/commande[@id_commande="com003"],
$akty in
$in/activite[@id_activite=$commande/mesurage/@id_aktivite],
$compoakt in $akty/composition_activite,
$famy in
$in/famille_cout[@id_famille_cout=$compoakt/@id_famille_kout]/composition_famille,
$pcmn in
$in/charge_indirecte/imputation[@id_pcmn_imputation=$famy/@id_pcmn_fam]
return
<activite>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in /client/commande/mesurage/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
*
sum(
for $uototal in $commande/mesurage/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite>
} </cout_indirect_commande>
|
Fonctionnement de la requête.
En boucle FOR, nous déclarons les variables.
La variable « $commande » est liée au premier
élément de la séquence « commande » du «
context node » ABC respectant le prédicat « id_commande »
= « com003 ».
La variable « $akty » est liée au premier
élément de la séquence « activite » qui est
sélectionné si un lien peut être établi avec
l'élément de la séquence « commande ».
Le lien est effectif si la comparaison des attributs «
id_activite » de l'élément activité et de «
id_aktivite » du premier élément de la séquence
mesurage ayant pour « context node »
« $commande » abouti.
Si le lien n'est pas établi, une itération examine
le second élément de la séquence « activite »,
etc...
La variable « $compoact » est liée au premier
élément de la séquence « composition_activite »
dont le « context node » est $akty (qui est liée à
« $commande » ).
La variable « $famy » est liée au premier
élément de la séquence « composition_famille »
de la séquence « famille_cout » si un lien est
établi.
Nous établissons un lien avec l'élément
« activite » par comparaison des valeurs des attributs «
famille_cout/@id_famille_cout » et « $compoakt/@id_famille_kout
».
Le lien est établi si il y a concordance, sinon, il y a
itération vers le second élément de la séquence
« famille_cout », pour une nouvelle évaluation.
La variable « $pcmn » accède au premier
élément « imputation » du « context node »
« charge_indirecte » .
Un lien est établi avec la variable « $famy »
par comparaison des valeurs des attributs « imputation/@id_pcmn_imputation
» à « $famy/@id_pcmn_fam ».
Une itération se produit pour le second
élément « imputation » , etc..., tant qu'un lien n'a
pas été établi.
Return fourni une séquence de résultats: «
montant_htva_impute » multiplié par « proportion_cf »
multiplié par « proportion » divisé par la somme de la
valeur des attributs « mesurage/@quantite »
sélectionnés.
Nous devons enfin multiplier ce résultat par la somme de
mesurages « mesurage/@quantite » se rapportant à cette
commande « com003 ».
Cette requête traitera les mesurages de la commande «
com003 » identiquement, et générera l'erreur que nous
évoquions ci-dessus.
Le résultat de la requête annonce un coût
indirect de 446,234 (Euro) pour cette commande.
<?xml version="1.0" encoding="UTF-8"?>
<cout_indirect_commande>446.2341931548628</cout_indirect_commande>
IF THEN ELSE.
Lorsque nous examinons les mesurages de « com003 »,
nous voyons qu'ils sont deux. Le premier 42 unités (kilomètres)
pour l'activité4 (transport).
Le second 2 unités (heure_production) pour
l'activité5 (production).
Afin que ces deux activités soient traitées
individuellement, nous avons utilisé IF THEN ELSE.
Nous avons 7 activités qui doivent être
traitées individuellement, et devons proposer 7 traitements
individuels.
Nous avons retenu la solution suivante.
Return sera suivi d'une expression IF posant comme condition que
l'activité à traiter soit l'activité1. Si il s'agit bien
de l'activité1, l'expression THEN autorise le calcul de la
requête.
La différence du traitement appliqué par «
Return » comparativement aux deux requêtes précédentes
est que nous ne considérons plus les quantités de mesurage dans
leur globalité, mais individuellement pour chaque activité.
Nous ajoutons donc un prédicat: « @id_aktivite="act1"
» .
for « $uo » in « $in »
/client/commande/mesurage/@quantite
devient
for « $uo » in « $in »
/client/commande/mesurage[@id_aktivite="act1"]/@quantite
return
if ($akty/@id_activite="act1")
then
<activite_1>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act1"]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
*
sum(
for $uototal in
$commande/mesurage[@id_aktivite="act1"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_1>
Si il ne s'agit pas de l'activité1, l'expression ELSE
évalue s'il s'agit de l'activité2 au quel cas l'expression THEN
autorise le traitement.
L'évaluation se fera sur base du prédicat «
@id_aktivite="act2" »
else
if ($akty/@id_activite="act2") then
<activite_2>{data($ ... etc...
|
Et ce répétitivement jusqu'à
l'activité6 au terme de laquelle il ne reste plus comme dernière
alternative que de traiter l'activité7.
else
<activite_7>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
etc
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_7>
) } </cout_abc_commande>
|
L'entièreté de cette requête est
imbriquée dans SUM( ), afin de sommer la séquence de
résultats. Nous reproduisons la requête complète
ci-dessous.
<cout_indirect_commande>
{
sum(
for $in in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")/ABC,
$commande in $in/client/commande[@id_commande="com003"],
$akty in
$in/activite[@id_activite=$commande/mesurage/@id_aktivite],
$compoakt in $akty/composition_activite,
$famy in
$in/famille_cout[@id_famille_cout=$compoakt/@id_famille_kout]/composition_famille,
$pcmn in
$in/charge_indirecte/imputation[@id_pcmn_imputation=$famy/@id_pcmn_fam]
return
if ($akty/@id_activite="act1")
then
<activite_1>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act1"]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
*
sum(
for $uototal in
$commande/mesurage[@id_aktivite="act1"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_1>
else
if ($akty/@id_activite="act2")
then
<activite_2>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act2"]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in
$commande/mesurage[@id_aktivite="act2"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_2>
else
if ($akty/@id_activite="act3")
then
<activite_3>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act3"]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in
$commande/mesurage[@id_aktivite="act3"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_3>
else
if ($akty/@id_activite="act4")
then
<activite_4>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act4"]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in
$commande/mesurage[@id_aktivite="act4"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_4>
else
if ($akty/@id_activite="act5")
then
<activite_5>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act5"]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in
$commande/mesurage[@id_aktivite="act5"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_5>
else
if ($akty/@id_activite="act6")
then
<activite_6>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act6"]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in
$commande/mesurage[@id_aktivite="act6"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_6>
else
<activite_7>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act7"]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in
$commande/mesurage[@id_aktivite="act7"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_7>
)
}
</cout_indirect_commande>
Le résultat généré est cette fois de
147,748 (Euro).
<?xml version="1.0" encoding="UTF-8"?>
<cout_indirect_commande>147.7485056679581</cout_indirect_commande>
Les « function » .
En procédant de la sorte, nous obtenons un résultat
différent, mais au prix d'une requête longue (121 lignes) et
complexe à lire.
Nous utiliserons les « functions » ou fonctions
proposées par XQuery afin d'alléger le code. Le bloc suivant
calculant la somme des mesurages pour une activité se
répète à sept reprises.
sum(
for $uo in $in
/client/commande/mesurage[@id_aktivite="act1"]/@quantite return
<uoeuvre>{data ($uo)}</uoeuvre>)
|
Nous le transformons en « function ».
Une « function » comporte les parties suivantes:
- la déclaration de « function » suivie de son
nom « declare function local: ici le nom ».
- les paramètres de la « function » et le type
retourné par la « function » (entre parenthèses). - le
corps de la « function » contenant les instructions de traitement.
Nous déclarons la « function » que nous nommons
: « activite »:
declare function local:activite
Nous avons un seul paramètre qui est « act1 » ou
« act2 », ..., ou « act7 ».
La variable « $ak » que nous déclarons prendra
comme argument un des sept « act... »
Ce paramètre est de type « atomic », et le
résultat de la « function » sera également une valeur
« atomic » (un nombre).
La déclaration de « function » complète
est:
declare function local:activite($ak as xs:anyAtomicType?)as
xs:anyAtomicType?
Le corps de la « function » est la partie de
imbriquée dans SUM.
{ sum(
for $uo in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")
//client/commande/mesurage[@id_aktivite=$ak]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
}
|
La « function » complète ci-dessous:
declare function local:activite($ak as xs:anyAtomicType?)as
xs:anyAtomicType? {
sum(
for $uo in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")
//client/commande/mesurage[@id_aktivite=$ak]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
};
|
Nous pouvons créer une seconde « function »
calculant la somme des mesurage par activité pour une commande
précise.
sum(
for $uototal in $commande/mesurage[@id_aktivite="act7"]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
|
Nous nommons cette « function » « activite2
».
declare function local:activite2($ak2 as xs:anyAtomicType?)as
xs:anyAtomicType? {
|
sum(
for $uototal in
doc("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")//
client/commande[@id_commande="com003"]/mesurage[@id_aktivite=$ak2]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
};
|
XQuery permet qu'une « function » se trouve au sein
d'un espace mémoire dédié ou bien dans la requête
elle même; nous retenons cette seconde possibilité.
Les deux « functions » se trouvent en préambule
de la requête.
Au sein de la requête, pour le calcul relatif à
l'activité1, nous appelons la « function » « activite
» par:
local:activite("act1")
et lui passons le paramètre « act1 »
et la seconde « function » qui reçoit le meme
paramètre par:
local:activite2("act1")
La requête complète devient:
declare function local:activite($ak as xs:anyAtomicType?)as
xs:anyAtomicType? {
sum(
for $uo in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")
//client/commande/mesurage[@id_aktivite=$ak]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
};
declare function local:activite2($ak2 as xs:anyAtomicType?)as
xs:anyAtomicType?
{
sum(
for $uototal in
doc("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")//
client/commande[@id_commande="com003"]/mesurage[@id_aktivite=$ak2]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
};
<cout_indirect_commande>
{
sum(
for $in in doc
("/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml")/ABC,
$commande in $in/client/commande[@id_commande="com003"],
$akty in
$in/activite[@id_activite=$commande/mesurage/@id_aktivite],
$compoakt in $akty/composition_activite,
$famy in
$in/famille_cout[@id_famille_cout=$compoakt/@id_famille_kout]/composition_famille,
$pcmn in
$in/charge_indirecte/imputation[@id_pcmn_imputation=$famy/@id_pcmn_fam]
return
if ($akty/@id_activite="act1")
then
<activite_1>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
local:activite("act1")
*
local:activite2("act1")
)}</activite_1>
else
if ($akty/@id_activite="act2")
then
<activite_2>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
local:activite("act2")*local:activite2("act2")
)}</activite_2>
else
if ($akty/@id_activite="act3")
then
<activite_3>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
local:activite("act3")*local:activite2("act3")
)}</activite_3>
else
if ($akty/@id_activite="act4")
then
<activite_4>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
local:activite("act4")*local:activite2("act4")
)}</activite_4>
else
if ($akty/@id_activite="act5")
then
<activite_5>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
local:activite("act5")*local:activite2("act5")
)}</activite_5>
else
if ($akty/@id_activite="act6")
then
<activite_6>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
local:activite("act6")*local:activite2("act6")
)}</activite_6>
else
<activite_7>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
local:activite("act7")*local:activite2("act7")
)}</activite_7>
)}
</cout_indirect_commande>
La requête est simplifiée, 85 lignes; si nous
souhaitons modifier la méthode de calcul des quantités de
mesurage, une seule modification de « function » sera
nécessaire, alors qu'il aurait fallu modifier à sept reprises
sans l'usage de « functions ».
Le résultat de cette requête est identique:
<?xml version="1.0" encoding="UTF-8"?>
<cout_indirect_commande>147.7485056679581</cout_indirect_commande>
Vérification du résultat.
Nous avons à nouveau souhaité vérifier le
résultat.
Ayant déjà vérifié le coût
d'une unité d'oeuvre pour l'activité5, nous vérifions
celle de l'activité 4. Commande « com003 » utilise 42
unités d'oeuvre de l'activité4 (mesurage « mes022
»).
La somme de tous les mesurages se rapportant à
l'activité4 est de 483 unités d'oeuvre.
Nous obtenions précédement pour l'activité5
un coût d'unité d'oeuvre de 18,178 (Euro)
<?xml version="1.0" encoding="UTF-8"?>
<requete_calcul_unite_oeuvre>18.17860066006601</requete_calcul_unite_oeuvre>
|
et de 2,652 (Euro) pour l'activité4.
<?xml version="1.0" encoding="UTF-8"?>
<requete_calcul_unite_oeuvre>2.6521739130434785</requete_calcul_unite_oeuvre>
Pour la commande « com003 », 42 unités de
l'activité4 sont utilisées: 2,652 * 42 = 111,384 (Euro). Pour
l'activité5, où 2 unités d'oeuvre sont mesurées:
18,18 * 2 = 36,36 (Euro).
Sommons ces deux valeurs: 111,384 + 36,36 = 147,744 (Euro) soit
le résultat fourni par la requête XQuery.
|