1 Initiation aux bases de données et à la programmation événementielle VBA sous ACCESS Cours N° 8 Support de cours rédigé par Bernard COFFIN Université Paris 10 – Nanterre 2007/2008
2 Des calculs sur les informations de la base de données Les requêtes sélection permettent d’obtenir des champs dont la valeur est calculée à partir de plusieurs données La requête commence par construire la relation R 0 par produit cartésien, projection, restriction 1.Le calcul se fait sur les données d’un seul enregistrement de la relation R 0 Le résultat est un champ (calculé) ajouté à ce même enregistrement Voir le cours N° 4
3 2.Le calcul se fait sur les données d’un groupe de plusieurs enregistrements de la relation R 0 Ces enregistrements doivent avoir un point commun : des champs qui ont la même valeur Ils sont agrégés pour n’en faire plus qu’un qui comprend : Une partie des champs communs (éventuellement tous) Les résultats des calculs Les enregistrements ainsi décrits forment une nouvelle relation R 1 ; c’est elle qui est le résultat de la requête Calculs « statistiques »
4 Select liste des champs de la projection et des fonctions d’agrégat From liste des relations dont on fait le produit cartésien Where clause de restriction éventuelle (ne peut pas porter sur les fonctions d’agrégat) Group By liste des champs servant à l’agrégation de plusieurs enregistrements Having autre clause de restriction (celle-ci peut porter sur les fonctions et champs d’agrégat) ; L’ordre des clauses doit être respecté On peut ajouter à la fin une clause de tri (Order By) Syntaxe
5 Calcule une valeur à partir des valeurs de tous les enregistrements agrégés Syntaxe : nom de la fonction (expression) La fonction d’agrégat Les fonctions disponibles sont : Sum : somme Avg : moyenne Min : le plus petit Max : le plus grand Count : compte StDev : écart type Var : variance First : premier Last : dernier
6 Group By liste des champs servant à l’agrégation de plusieurs enregistrements Tous les enregistrements de la relation de base R 0 dont tous les champs qui suivent « Group By » ont la même valeur (d’un enregistrement à l’autre) sont agrégés pour ne former qu’un seul enregistrement dans la relation résultat de la requête R 1 Having autre clause de restriction portant sur les fonctions d’agrégat et les champs servant à l’agrégation ; La syntaxe est la même que pour une clause Where, mais elle porte sur les fonctions et champs d’agrégat de la projection Elle ne peut pas porter sur des champs qui ne servent pas à l’agrégation (utiliser Where pour ces restrictions-là) Les nouvelles clauses
7 Tous les champs sur lesquels on fait la projection (clause Select) doivent servir dans la clause d’agrégat (Group By) ou être le résultat d’une fonction d’agrégat Mais un champ peut figurer dans la clause d’agrégat sans servir à la projection De même, les champs utilisés dans la restriction Where peuvent ne pas servir à la projection (comme d’habitude) Important !
8 Exemple 1 CP : N° auteur Sexe Nom auteur Prénom auteur Année naissance Année décès tabAuteurtabŒuvre CP : N° œuvre CE : Référence auteur Titre Nombre d’œuvres par auteur ? Select [N° auteur], [Nom auteur] & " " & [Prénom auteur] As Identité, count([N° œuvre]) As Nombre_œuvres From tabAuteur, tabŒuvre Where [Référence auteur] = [N° auteur] Group By [N° auteur], [Nom auteur] & " " & [Prénom auteur] ; Produit cartésien des deux tablesRestriction pour respecter le lien logiqueProjection sur trois champs Les noms symboliques Identité et Nombre_oeuvres ne sont pas utilisables dans les autres clauses Agrégation
9 Supprimer le champ [N° auteur] ? Select [N° auteur], [Nom auteur] & " " & [Prénom auteur] As Identité, count([N° œuvre]) As Nombre_œuvres From tabAuteur, tabŒuvre Where [Référence auteur] = [N° auteur] Group By [N° auteur], [Nom auteur] & " " & [Prénom auteur] ; S’il n’y a pas d’homonymes, même nom et même prénom, on aura autant d’enregistrements dans la relation résultant de la requête, mais… on ne pourra pas utiliser le [N° auteur] dans un objet dont la requête serait la source ou le contenu
10 Se contenter du [Nom auteur] au lieu du champ calculé ? Select [N° auteur], [Nom auteur], count([N° œuvre]) As Nombre_ œuvres From tabAuteur, tabŒuvre Where [Référence auteur] = [N° auteur] Group By [N° auteur], [Nom auteur]; En cas d’homonymes, même nom (par exemple Charlotte et Emily BRONTE), les enregistrements de tous les homonymes seront agrégés dans la relation résultant de la requête On aura donc un seul enregistrement pour les deux sœurs Bronte Mais si on ajoute [N° auteur] dans la clause d’agrégat… on aura un enregistrement pour chacune d’elle avec le même nom, et des valeurs de Nombre_œuvres différentes (potentiellement) Si on ajoute [N° auteur] dans la projection… MAIS PAS dans la clause d’agrégat… la requête est fausse (erreur de syntaxe !)
11 Exemple 2 : tabCommande CP : N° Commande CE : Réf Client Date commande tabLien_Cde_Pdt CP :CE : Réf Commande CE : Réf Produit Quantité commandée tabClient CP : N° client Nom client Adresse tabProduit CP : Code produit Nom produit Prix Unitaire calculer le montant total d’une commande
12 Pour chaque ligne de la commande (un produit commandé), il faut faire le produit de la quantité commandée par le prix unitaire Puis il faut faire la somme de ces valeurs pour l’ensemble de la commande Select [Réf commande], sum([Quantité commandée]*[Prix unitaire]) as Prix_total From tabLien_Cde_Pdt, tabProduit Where [Réf produit] = [Code produit] Group By [Réf commande];
13 Chiffre d’affaire du client ? C’est la somme des montants de toutes les commandes qu’il a passées Select [Réf client], sum([Quantité commandée]*[Prix unitaire]) as Chiffre_affaire From tabCommande, tabLien_Cde_Pdt, tabProduit Where [N° commande] = [Réf commande] and [Réf produit] = [Code produit] Group By [Réf client];
14 Utilisation dans un formulaire L’obligation d’utiliser les champs de la projection dans l’agrégation empêche souvent de faire de la requête avec calcul statistique la source du formulaire principal On utilise alors un contrôle dont la requête puisse être la source (sous-formulaire) ou le contenu (zone de liste) Il faut veiller à ce que les résultats affichés par ce moyen soient mis à jour convenablement ! Exemple Saisie d’une commande client. On a ajouté un champ [taux de remise exceptionnelle] à la table commande (ce taux de remise est valable pour toute la commande et uniquement pour elle) Ce taux est décidé par le commercial qui utilise l’application ; pour cela il doit visualiser à tout moment le montant de la commande et le chiffre d’affaire du client (incluant la commande en cours de saisie)
15 Conception du formulaire La source du formulaire est une requête fondée sur la table de description des commandes (tabCommande) Des zones de texte permettent de saisir la date de la commande et le taux de remise accordé (valeur par défaut : zéro) ; elles sont liées aux champs correspondants Une zone de liste déroulante permet de sélectionner le client (contenu classé par nom et adresse) Un sous-formulaire lié au formulaire principal (lien père / fils) permet la saisie des lignes de la commande et l’affichage des prix unitaires Une zone de liste déroulante permet de sélectionner le produit (contenu classé par nom) Le prix unitaire est affiché au moyen d’une zone de texte liée ; son format est celui d’une étiquette (il n’est pas modifiable par ce traitement) La quantité commandée est saisie grâce à une zone de texte liée au champ correspondant Deux sous-formulaires permettent d’afficher respectivement le chiffre d’affaire du client (commande en cours non comprise) et les montants totaux de la commande (avant et après réduction)
16 Sous-formulaire pour la saisie des lignes de la commande Sous-formulaire pour afficher les totaux de la commande Sous-formulaire pour afficher le chiffre d’affaire du client Zones de textes liées ; on leur a donné un aspect d’étiquettes parce que ce ne sont pas des zones de saisie
17 La source du formulaire formSaisie_commande est une requête fondée sur la table de description des commandes (tabCommande) SELECT * FROM tabCommande; Des zones de texte permettent de saisir la date de la commande et le taux de remise accordé (valeur par défaut : zéro) ; elles sont liées aux champs correspondants 1.ztDate – Source contrôle [Date commande] 2.ztRemise – Source contrôle : [Taux_remise_exceptionnelle] Une zone de texte permet d’afficher le numéro de la facture ztNuméro – Source contrôle : [N° commande] Son aspect est celui d’une étiquette (pas de saisie possible) ; ce contrôle ne peut pas devenir actif : Private Sub ztNuméro_GotFocus() Choix_client.SetFocus End Sub
18 Une zone de liste déroulante permet de sélectionner le client (contenu classé par nom et adresse) Choix_client Source contrôle : [Réf client] Contenu : SELECT [N° client], [Nom client] & " " & [Adresse] FROM tabClient ORDER BY [Nom client], Adresse; Colonne liée : 1 Nbre colonnes : 2 Largeur colonnes : 0cm; 7cm
19 Un sous-formulaire lié au formulaire principal (lien père / fils) permet la saisie des lignes de la commande et l’affichage des prix unitaires sfLigne_commande Objet lié : formSaisie_ligne Source du formulaire (formSaisie_ligne): SELECT tabLien_Cde_Pdt.*, [Prix unitaire] FROM tabLien_Cde_Pdt INNER JOIN tabProduit ON tabProduit.[Code produit]=tabLien_Cde_Pdt.Réf_produit ORDER BY Réf_produit; Champ père : [N° commande] Champ fils : [Réf_commande]
20 Une zone de liste déroulante permet de sélectionner le produit (contenu classé par nom) Choix_produit Source contrôle : [Réf_produit] Contenu : SELECT [Code produit], [Nom produit] FROM tabProduit ORDER BY [Nom produit]; Colonne liée : 1 Nbre colonnes : 2 Largeur colonnes : 0cm; 7cm
21 Le prix unitaire est affiché au moyen d’une zone de texte liée ; son format est celui d’une étiquette (il n’est pas modifiable par ce traitement) ztPrix Source contrôle : [Prix unitaire] Format : monétaire Ce contrôle ne peut pas devenir actif Private Sub ztPrix_Enter() Choix_produit.SetFocus End Sub La quantité commandée est saisie grâce à une zone de texte liée au champ correspondant ztQuantité Source contrôle : [Quantité commandée]
22 Deux sous-formulaires permettent d’afficher respectivement le chiffre d’affaire du client (commande en cours non comprise) et les montants totaux de la commande (avant et après réduction) 1.Chiffre d’affaire : sfChiffre_d’affaires Objet lié : formChiffre_d’affaires Source du formulaire (formChiffre_d’affaires) : SELECT [Réf_client], Sum([Quantité commandée]*[Prix unitaire]*(1-Taux_remise_Exceptionnelle/100)) AS Total_client FROM tabCommande, tabLien_Cde_Pdt, tabProduit WHERE [N° commande]<>forms!formsaisie_commande!ztNuméro And [N° commande]=[Réf_commande] And [Réf_produit]=[Code produit] GROUP BY [Réf_client]; Champ père : formSaisie_commande.[Réf_client] Champ fils : [formChiffre_d’affaires].[Réf_client] Une zone de texte liée : ztChiffre Source contrôle : Total_client
23 2.Chiffre d’affaire : sfTotal Objet lié : formTotal_commande Source du formulaire (formTotal_commande) : SELECT [Réf_commande], Sum([Quantité commandée]*[Prix unitaire]) AS Prix_total FROM tabLien_Cde_Pdt, tabProduit WHERE [Réf_produit]=[Code produit] GROUP BY [Réf_commande]; Champ père : [Réf_commande] Champ fils : [N° commande] Une zone de texte liée : ztTotal_brut Source contrôle : Prix_total Une zone de texte liée : ztChiffre Source contrôle : =[Prix_total]*(1-Formulaires!formSaisie_commande!ztRemise.Value/100) La valeur de la propriété « Source contrôle » est ici une formule (elle doit commencer par « = ») utilisant des valeurs de champs et de contrôles (ici d’un autre formulaire, qui doit être ouvert). La valeur du contrôle est automatiquement mise à jour à chaque modification de l’une des valeurs qui servent à la calculer
24 Il faut veiller à ce que les résultats affichés par ce moyen soient mis à jour convenablement ! Si on modifie un enregistrement de la table tabLien_Cde_Pdt, a fortiori si on en crée un nouveau, il faut recalculer le montant total de la commande Private Sub Form_AfterUpdate() Forms!formSaisie_commande!sfTotal.Requery End Sub On ne pourrait pas modifier le chiffre d’affaires parce que l’enregistrement du formulaire principal pourrait ne pas avoir été mis à jour (taux de remise) et on obtiendrait des données affichées incohérentes. C’est pour cela qu’on n’affiche que le montant du chiffre d’affaires ne comprenant pas la commande en cours.
25 Il faut veiller à ce que les résultats affichés par ce moyen soient mis à jour convenablement ! Si on modifie la valeur du taux de remise exceptionnelle ztRemise, il faut recalculer le montant total de la commande Private Sub ztRemise_BeforeUpdate(Cancel As Integer) sfTotal.Requery End Sub Pour empêcher l’utilisateur d’essayer d’atteindre le chiffre d’affaires : Private Sub sfChiffre_d_affaires_Enter() Screen.PreviousControl.SetFocus End Sub Cette procédure rend actif le dernier contrôle qui l’était sur l’écran (Screen)
26