[EXCEL-POWERQUERY] :: Simuler la fonction FILTRE (simplifiée) via une requête POWERQUERY pour les versions Excel antérieures à Office 365

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

oguruma

XLDnaute Impliqué
Bonjour le Forum,

La fonction FILTRE est apparue sauf erreur à la sortie de Office 365.
Il est donc intéressant de reproduire cette fonction pour les utilisateurs qui sont restés par exemple en version 2016 ou qui ne possèdent pas cette fonction.
Pour cela nous disposons d'un merveilleux outil à ne plus mettre de côté POWERQUERY directement intégré dans la version Excel 2016.
Pour les versions antérieures à 2016 (2013, 2010) PowerQuery existait sous forme de d'add-on à installer avec ses défauts de jeunesse. Oublions !

Le but est de reproduire ceci
A partir d'un tableau de données comme celui-ci
1776779406298.png


Construire un onglet permettant d'effectuer des recherches filtrées comme le ferait la fonction FILTRE.
1776779480013.png


On renseigne la colonne à filtrer
1776779509440.png


puis la valeur recherchée
1776779535474.png


et la recherche est lancée automatiquement.

Voici donc le montage à effectuer pas à pas.

1. Un tableau de données structuré : T_BDD_VENTES dans notre exemple
1776779650932.png

2. Une feuille de paramètre appelée ici Param (avec les commentaires dans le cadre de l'exemple)
1776779748136.png

Ces paramètres seront nécessaires à la construction de la requête PowerQuery.

3. Préparation paramètres pour la fontion FILTRE simulée (Colonne filtrée, valeur cherchée)
1776779901651.png


Nous avons les deux champs nommés comme ceux-ci. Llibre à vous de choisir d'autres noms mais dans ce cas il faudra adapter le code M qui sera détaillé ci-dessous.
1776779999966.png


4. La partie POWERQUERY
Elle est composée des éléments suivants :
1776780174943.png


La requête T_FILTRE simule la fonction FILTRE de Excel.

Voici le code
PowerQuery:
let

    //******************************************************************
    //  On récupère les paramètres
    //******************************************************************
    STR_Table=fnGetName("NOM_TABLE"),
    STR_TableAff=fnGetName("NOM_TABLE_AFF"), 
    STR_Col=fnGetName("NOM_COL_FILTRE"),
    STR_Val=fnGetName("VALEUR_FILTRE"),   

    //******************************************************************
    //  On récupère la table à filtrer
    //******************************************************************
    Source = Excel.CurrentWorkbook(){[Name=STR_Table]}[Content],     
    
    //******************************************************************
    //  On construit la liste des colonnes à afficher
    //******************************************************************
    LST_COL_AFFICHE=Table.ToList(fnGetList(STR_TableAff)),

    //*****************************************************************************************
    //  On va construire une table vide si aucune valeur
    // pour éviter le plantage erreur PowerQuery si la valeur recherchée n'est pas renseignée
    //*****************************************************************************************
    TB_NULL= #table(LST_COL_AFFICHE,{}),   
    
    //******************************************************************
    //  On pose le filtre
    //  avec la précaution si la valeur recherchée n'est pas renseignée
    //******************************************************************
    TB_FILTRE = if STR_Val is null then TB_NULL else fnFILTREV2016(Source, STR_Col, STR_Val),

    //******************************************************************
    //  On sélectionne les colonnes à afficher
    // Idem même précaution si la valeur recherchée n'est pas renseignée
    //******************************************************************
    TB_SELECT_COLUMN = if STR_Val is null then TB_NULL else Table.SelectColumns(TB_FILTRE,LST_COL_AFFICHE)
in
   TB_SELECT_COLUMN

Elle fait appel aux fonction suivantes
Code:
let fnFILTREV2016= (pTable as table, pCol as text, pValue as any) as table =>

//**********************************************************************
// Cette fonction permet de simuler la fonction FILTRE de Excel
// Ici l'opérateur est EGAL pour simmplifier les choses
//**********************************************************************

        let

        //**************************************************************
        // On récupèer les paramètres
        //**************************************************************
            Source = pTable,
            STR_COL_SELECT=pCol,
            STR_COL_VALUE=pValue,

        //**************************************************************
        // Les colonnes à afficher sont transformées en liste
        //**************************************************************
            LST_COL_SELECT= {STR_COL_SELECT},
        
        //**************************************************************
        // On récupère les colonnes de la table des données
        //**************************************************************
            LST_COLUMNS=Table.ColumnNames(Source),

        //******************************************************************
        // Par sécurité on fait l'intersection avec les colonnes à afficher
        //******************************************************************
            LST_INTERSECT_FILTRE=List.Intersect({LST_COLUMNS,LST_COL_SELECT}),
            STR_COL_FILTRE=if List.IsEmpty(LST_INTERSECT_FILTRE) then LST_COLUMNS{0} else LST_INTERSECT_FILTRE{0},

        //**************************************************************
        // On règle le cas où on filtre sur une valeur numérique
        //**************************************************************
            convertType= if STR_COL_VALUE is text then """" & Text.From(STR_COL_VALUE) & """" else Text.From(Number.From(STR_COL_VALUE)) ,

        //**************************************************************
        // Construction du filtre avec un each indirect
        //**************************************************************
            STR_EVAL="each ["& STR_COL_FILTRE & "] = " & convertType,           

        //**************************************************************
        // Expression.Evaluate c'est un peu le INDIRECT de Excel
        //**************************************************************
            EVAL_FILTRE=Expression.Evaluate(STR_EVAL),   

        //**************************************************************
        // Et on renvoie la table filtrée
        //**************************************************************
            TB_FILTRE = Table.SelectRows(Source, EVAL_FILTRE)
        in
            TB_FILTRE
in 
    fnFILTREV2016
    
    
let
    fnGetName = (pName as text) as any =>
        let
            Source = Excel.CurrentWorkbook(){[Name=pName]}[Content],           
            STR_Val = Source{0}[Column1]
        in
            STR_Val
in
    fnGetName
    
let 
    fnGetList = (pName as text) as any =>
        let
            Source = Excel.CurrentWorkbook(){[Name=pName]}[Content],
            LST_COL=Table.ColumnNames(Source),
            TBL_ChangTypeColumn1 = Table.TransformColumnTypes(Source,{{LST_COL{0}, type text}}),
            STR_Val = TBL_ChangTypeColumn1
        in
            STR_Val
in 
    fnGetList

fnGetList : est utilisée pour récupérer la liste des colonnes à afficher précisées dans le tableau des paramètres
1776780511638.png


fnGetName : Permet de récupérer un paramètre renseigné dans un champ nommé

Autre exemple avec une autre personnalisation des colonnes à afficher
1776780730466.png


1776780695148.png


5. Mise à jour automatique à l'issue du choix de la valeur recherchée
On passera par du code VBA en faisant appel aux événements de la feuille (onglet) T_FILTRE (Feuil1)
PowerQuery:
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)

 If Not Application.Intersect(Target, Range("NOM_COL_FILTRE")) Is Nothing Then
     Range("VALEUR_FILTRE") = ""
     Exit Sub
 End If
 
 If Not Application.Intersect(Target, Range("VALEUR_FILTRE")) Is Nothing Then
     If Range("VALEUR_FILTRE") <> "" Then ActiveWorkbook.Connections("Requête - T_FILTRE").Refresh
 End If
End Sub

bien entendu adapter le champ nommé Range("NOM_COL_FILTRE") et le nom de la requête ActiveWorkbook.Connections("Requête - T_FILTRE").Refresh si vous envisagez d'autres noms
 

Pièces jointes

- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

Retour