Compter nombre des RVD selon plusieurs critères -VBA

Salut tout le monde.

Je me tourne vers vous aujourd’hui parce que je ne comprends pas comment résoudre mon problème.

J’ai un tableau des RDV qu’est alimenté régulièrement via un Userform et qui marche bien.

Je cherche à faire des statistiques en fin d’année via un code VBA ;

Le but est compter le nombre des RDV selon les critères suivant :

  • Année.
  • Centre
  • Nature du RDV (Biologique ou Radiologique)
  • Et nature de la prise en charge (PRÊT ou DON)
Puis faire les totaux.

Voir les résultats voulu à la feuille « STAT ».

NB : avec les formules c possible mais pour chaque année les centres peuvent changer.

Je vous mets mon fichier en pièce jointe a signalé que j’ai laissé que l’année 2018.

Merci à vous.

16stat-zving.xlsm (53.20 Ko)

Bonjour,

Une proposition TCD (tableau croisé dynamique).

A te relire.

Cdlt.

11stat-zving.xlsm (60.83 Ko)

Merci à ta réponse mais c c possible en VBA parce que j'ai déjà un userforme pour le saisi des RDV

bonjour

comme Jean-Eric

et j'ajoute que tu devrais supprimer toute macro (formulaire, stat...)

la saisie dans un chouette Tableau comme tu l'as fait se réalise directement dedans

fais tes stats par un TCD.

bien plus souple d'emploi que ton onglet state

note : n'oublie pas de créer une colonne "Terminé" pour différencier les RDV effectivement terminés de ceux non terminés. Le filtre te permet de ne voir au quotidien que les non terminés. Se fier à la date ne suffit pas, car il y a des annulations/reports non encore planifiés.

bon travail

amitiés

Re,

La version VBA !...

Cdlt.

46stat-zving.xlsm (64.14 Ko)

Re,

La version VBA !...

Cdlt.

Stat-zving.xlsm

Bonjour Jean-Eric.

Je me demandais justement à quoi ressemblait ta version VBA

C'était juste l'actualisation du TCD

Tu aurais pu utliser son onglet feuille 1 pour la sélection de l'année et l'actualisation à partir de son userform

Re,

L'Userform fonctionne parfaitement, car il ne comporte pas de procédures VBA !...

J’ai un tableau des RDV qu’est alimenté régulièrement via un Userform et qui marche bien.

Cdlt.

merci bien.

mais SVP pouvez vous m'aider sans TCD.

Re,

Envoie ton fichier avec un Userform fonctionnel, et je reverrai le fichier, avec un TCD (en VBA).

Cdlt.

Bonjour, Salut Jean-Eric, jmd !

Solution macro utilisant le Userform :

Dim Brv, d As Object

Private Sub CommandButton1_Click()
    Dim ETt, Tmp, k, i&, a%, j%
    If ComboBox1.ListIndex > -1 Then a = CInt(ComboBox1.Value) Else Exit Sub
    For i = 2 To UBound(Brv)
        If Brv(i, 9) = a Then
            k = Brv(i, 7)
            j = (1 + (Brv(i, 5) = "BIOLOGIQUE")) * 2
            j = j + 2 + (Brv(i, 4) = "PRÊT")
            If Not d.exists(k) Then d(k) = Array(k, 0, 0, 0, 0, 0)
            Tmp = d(k): Tmp(j) = Tmp(j) + 1: Tmp(5) = Tmp(5) + 1: d(k) = Tmp
        End If
    Next i
    Tmp = d.items
    With Worksheets("state").Range("A3")
        .CurrentRegion.Clear
        With .Resize(2, 6)
            ETt = .Value
            ETt(1, 1) = a: ETt(1, 2) = "BIOLOGIQUE": ETt(1, 4) = "RADIOLOGIQUE"
            ETt(2, 2) = "PRÊT": ETt(2, 3) = "DON": ETt(2, 4) = ETt(2, 2)
            ETt(2, 5) = ETt(2, 3): ETt(2, 6) = "Total"
            .Value = ETt
            .HorizontalAlignment = xlCenter
            For i = 2 To 4 Step 2
                .Cells(1, i).Resize(, 2).Merge
            Next i
            .Borders.Weight = xlThin
        End With
        With .Offset(2).Resize(d.Count, 6)
            .Value = WorksheetFunction.Transpose(WorksheetFunction.Transpose(Tmp))
            .Offset(, 1).Resize(, 5).HorizontalAlignment = xlCenter
            .Borders.Weight = xlThin
            .Sort key1:=.Cells(1, 1), order1:=xlAscending, Header:=xlNo
        End With
        With .Offset(d.Count + 2).Resize(, 6)
            .Cells(1, 1) = "Total"
            .Offset(, 1).Resize(, 5).HorizontalAlignment = xlCenter
            .Borders.Weight = xlThin
            For i = 2 To 6
                .Cells(1, i) = WorksheetFunction.Sum(.Offset(-d.Count, i - 1).Resize(d.Count, 1))
            Next i
        End With
        .Worksheet.Activate
    End With
    Unload Me
End Sub

Private Sub UserForm_Initialize()
    Dim i&, aa
    Brv = Worksheets("RDV").Range("A1").CurrentRegion
    Set d = CreateObject("Scripting.Dictionary")
    For i = 2 To UBound(Brv)
        d(Brv(i, 9)) = ""
    Next i
    aa = d.keys
    Select Case d.Count
        Case 0: Unload Me: Exit Sub
        Case 1: ComboBox1.AddItem aa(0)
        Case Else: ComboBox1.List = aa
    End Select
    d.RemoveAll
End Sub

Cordialement.

edit : peut-être pas totalement optimal, car je n'ai vu ta ligne de totaux en bas de tableau qu'à la fin, et l'ai construite avec un rajout. Elle aurait sans doute pu être intégrée en amont.

Bonjour MFerrand.

Compliments pour le Vba

J'avais pensé à une option de Tcd suivie d'un copié collé spécial et la suppression du tcd ensuite... pour faire discret lol

merci MFerrand ca marche bien;

vu tu ajouter des commentaires pour bien comprendre votre code.

Je ne mets généralement pas de commentaires (sauf parfois des balises repères très réduites) car ça me gêne pour lire le code, il faut le chercher au milieu de commentaires . Les commentaires sont généralement superflus dès qu'on connaît un peu VBA, et toujours insuffisants lorsqu'on est novice, car même en étant largement plus longs que la procédure ils n'expliquent tous les détails qui ont conduit à chaque choix élémentaire...

On va faire une exception...

Pour ordre : le caractère deux-points (:) inséré dans une ligne (sauf lorsqu'il fait partie d'un texte mis entre guillemets) est un séparateur de lignes de code, qui permet d'insérer plusieurs lignes de code sur la même ligne physique ;

le caractère underscore ( _) précédé d'une espace en fin de ligne physique indique que ce qui suit à la ligne suivante fait partie de la même ligne de code, c'est un caractère de continuité de ligne.

L'initialisation commentée :

Private Sub UserForm_Initialize()
    Dim i&, aa
    'Récupération des données sous forme tableau VBA, variable module car sera
    ' réutilisée par la procédure bouton
    Brv = Worksheets("RDV").Range("A1").CurrentRegion
    'Création dictionnaire, variable niveau module également, utilisé aussi par
    ' procédure bouton
    Set d = CreateObject("Scripting.Dictionary")
    'Boucle sur les lignes du tableau, on récupère l'année comme clé d'élément dico,
    ' il n'y aura qu'un élément dico par année figurant dans le fichier, pas de
    ' valeur, on ne s'en sert que pour obtenir un seul élément par année
    For i = 2 To UBound(Brv)
        d(Brv(i, 9)) = ""
    Next i
    'On affecte les clés de dico à un tableau - NB: j'opère une modification pour le cas
    ' de lancement sur un tableau RDV ne contenant aucune donnée ! On n'aurait recueilli
    ' aucune année, ce qui engendrerait une erreur...
    If d.Count > 0 Then aa = d.keys Else Unload Me: Exit Sub 'ligne modifiée
    'NB:la modification ci-dessus élimine le cas 0 ci-dessous
    ' on distingue le cas 1 car on ne peut affecter la liste des années par List dans ce
    ' cas (obligation d'utiliser alors AddItem)
    ' Donc on affecte la liste des années à la Combo
    Select Case d.Count
        Case 1: ComboBox1.AddItem aa(0)
        Case Else: ComboBox1.List = aa
    End Select
    'On supprime tous les éléments dico (ils ne reserviront pas pour la phase suivante)
    ' En fin de proc.d'initialisation, le Userform s'affiche
    d.RemoveAll
End Sub

Et la procédure principale :

Private Sub CommandButton1_Click()
    Dim ETt, Tmp, k, i&, a%, j%
    'Si sélection d'une année dans la Combo, on la récupère dans la variable a,
    ' sinon... rien ! A l'utilisateur de réagir
    If ComboBox1.ListIndex > -1 Then a = CInt(ComboBox1.Value) Else Exit Sub
    'Boucle sur les lignes de tableau de données qui a été conservé dans la
    ' variable module Brv
    For i = 2 To UBound(Brv)
    'On ne s'intéresse qu'aux lignes correspondant à l'année choisie
        If Brv(i, 9) = a Then
    'On recueille le Centre dans la variable k
            k = Brv(i, 7)
    'On définit dans la variable j (Integer) un numéro de colonne de tableau à
    ' une dimension à partir des mentions 'BIOLOGIQUE' en E et 'PRÊT' en D (on
    ' considère que si Faux à ce test on a 'RADIOLOGIQUE' et 'DON')
    'Le test est fait au moyen d'expressions booléennes intégrées dans le calcul,
    ' je te laisse le vérifier sachant que True=-1 et False=0... le résultat
    ' correspond à la colonne du tableau résultat final diminuée de 1 (on part
    ' d'un indice 0 pour la 1re colonne
            j = (1 + (Brv(i, 5) = "BIOLOGIQUE")) * 2
            j = j + 2 + (Brv(i, 4) = "PRÊT")
    'Les clés des éléments dico qu'on va créer sont les noms de Centres (on l'a en k)
    'On teste donc si l'élément n'existe pas, auquel cas on lui affecte un tableau
    ' initial dont le 1er élément est également le nom du Centre, et les 5 éléments
    ' qui suivent, cinq 0 [on peut affecter un tableau comme valeur d'élément dico]
            If Not d.exists(k) Then d(k) = Array(k, 0, 0, 0, 0, 0)
    'Que l'élément préexistait ou qu'il vienne d'être créé, on recueille sa valeur
    ' (un tableau) dans la variable Tmp, on augmente l'élément de ce tableau
    ' correspondant à la colonne calculée de 1, et l'élément final (total) de 1,
    ' et on réaffecte le tableau modifié à l'élément dico
            Tmp = d(k): Tmp(j) = Tmp(j) + 1: Tmp(5) = Tmp(5) + 1: d(k) = Tmp
        End If
    Next i
    'Une fois tous les éléments dico créés et modifiés au fil du parcours des lignes
    ' pour incrémenter le nombre de rendez-vous selon ses caractéristiques, on affecte
    ' la totalité des valeurs (ou items) de dico au tableau Tmp, lequel sera alors un
    ' tableau à une dimension dont chaque élément est constitué par un tableau
    Tmp = d.items
    'on passe maintenant sur la feuille 'state' (sans bouger ! la feuille sur laquelle
    ' figure le bouton de lancement demeurera la feuille active jusqu'à la fin) et on
    ' cible la cellule A3 (la cellule de ton choix)
    With Worksheets("state").Range("A3")
    'On commence par éliminer la 'région courante' de A3, soit tout tableau antérieur
        .CurrentRegion.Clear
    'On rajuste notre cible à partir de A3 pour viser une plage de 2 lignes et 6 colonnes
    ' où se situera l'en-tête de notre tableau résultats
        With .Resize(2, 6)
    'On affecte les valeurs de cette plage (qui est vide) à une variable RTt, on obtient
    ' ainsi un tableau qui va nous servir à le garnir des mentions d'en-tête, ce qu'on fait
            ETt = .Value
            ETt(1, 1) = a: ETt(1, 2) = "BIOLOGIQUE": ETt(1, 4) = "RADIOLOGIQUE"
            ETt(2, 2) = "PRÊT": ETt(2, 3) = "DON": ETt(2, 4) = ETt(2, 2)
            ETt(2, 5) = ETt(2, 3): ETt(2, 6) = "Total"
    'Et on réaffecte ce tableau à la plage
            .Value = ETt
    ' qu'on met ensuite en forme : centrage, fusions de cellules, bordures
            .HorizontalAlignment = xlCenter
            For i = 2 To 4 Step 2
                .Cells(1, i).Resize(, 2).Merge
            Next i
            .Borders.Weight = xlThin
        End With
    'On passe aux données comptabilisées, et on cible alors à partir de A3
    ' une plage décalée de 2 lignes et redimensionnée en nb de lignes au nb
    ' d'éléments dico, et 6 colonnes
        With .Offset(2).Resize(d.Count, 6)
    'On affecte notre tableau Tmp à la plage ainsi définie, ce qui se réalise
    ' compte tenu de sa constitution (tableau unidimensionnel de tableaux) par
    ' une double transposition, qui aboutit à placer les données comme on le
    ' souhaite dans la plage
            .Value = WorksheetFunction.Transpose(WorksheetFunction.Transpose(Tmp))
    'On procède à une mise en forme, comme précédemment : centrage (sauf 1re col.),
    ' bordures
            .Offset(, 1).Resize(, 5).HorizontalAlignment = xlCenter
            .Borders.Weight = xlThin
    'Tri pour remettre les Centres dans l'ordre alphabétique
            .Sort key1:=.Cells(1, 1), order1:=xlAscending, Header:=xlNo
        End With
    'On cible maintenant (toujours à partir de A3) une cellule décalée du nombre de
    ' lignes déjà utilisées (nb éléments dico-Centres + 2-en-tête) qu'on redimensionne
    ' sur 6 colonnes pour constituer la ligne de totaux
        With .Offset(d.Count + 2).Resize(, 6)
    'Mention 'Total' dans la 1re cellule et mise en forme : centrage (sauf première),
    ' bordures
            .Cells(1, 1) = "Total"
            .Offset(, 1).Resize(, 5).HorizontalAlignment = xlCenter
            .Borders.Weight = xlThin
    'Puis on calcule les totaux de chaque colonne pour les affecter à cheque cellule
    ' (sauf la 1re)
            For i = 2 To 6
                .Cells(1, i) = WorksheetFunction.Sum(.Offset(-d.Count, i - 1).Resize(d.Count, 1))
            Next i
        End With
    'On active la feuille pour montrer les résultats à l'utilisateur (on est en train
    ' d'opérer dans une plage, .Worksheet nous renvoie la feuille parente de la plage)
        .Worksheet.Activate
    End With
    'On décharge le Userform
    Unload Me
End Sub

Cordialement.

merci a vous et a bien tôt.

Merci aussi car c'est très enrichissant pour moi aussi.

Rechercher des sujets similaires à "compter nombre rvd criteres vba"