Icône de la ressource
Bonjour,
cet utilitaire fait suite au post :https://excel-downloads.com/threads...de-donnees-en-lignes-via-powerquery.20080390/ où il y a eu différentes contributions de Mromain et de Cousinhub. Merci à eux.
La proposition de Mromain a été retenue et implémentée dans cet outil. La requête a été uniquement modifiée de manière à la rendre paramétrable en fonction du contexte.

L'interface d'accueil se présente comme suit :
1703541847638.png


  1. Renseigner le fichier .csv à traiter. Ce nom de fichier est passé en paramètre dans la requête d'importation des données sources.
  2. Par défaut l'outil propose des noms d'onglets qui vont accueillir les données sources et les différentes solutions. Ceux-ci sont modifiables. Ils sont directement reportés dans les onglets paramètres de calculs et Params.
  3. Le critère de bloc : sa présence est vitale. C'est lui qui va identifier le nombre de blocs à traiter afin de dégrouper les lignes en colonnes. Un contrôle cohérence et de détection de ce critère est automatiquement effectué. Si le critère n'est pas identifié il ne sera pas possible de démarrer le dégroupage. En effet le Nbr de blocs sera à zéro, ce qui rendront impossibles les traitements (des contrôles sont présents dans le code des macros et formules)
  4. Renseigner le séparateur des étiquettes et valeurs. Par défaut on considère ce format ETIQUETTE;VALEUR. Ce caractère est passé en paramètre dans la requête PowerQuery qui va importer les données sources
  5. Par défaut l'outil considère que le fichier source comporte des titres de colonnes. Ce paramètre est aussi passé à la requête PowerQuery de Mromain afin de tenir compte de la ligne de renommage présente dans la requête. Voir le code.
Paramètres de calculs - Onglet [Paramètres de calculs]

1703542482975.png


J'invite ici les débutants à consulter les formules qui se trouvent dans cette zone. Figurent des astuces pour récupérer la lettre de la colonne ou calculer la dimension de la plage à traiter à partir de deux paramètres seulement : adresse source des données et le critère de bloc. Ces deux informations permettent de calculer les paramètres ci-dessous.
Je les invite également à "détourer" les différents noms de champs. On y montre l'utilisation de la fonction LAMBDA pour le dégroupage par formules. On y retrouve aussi la puissance de la fonction DECALER pour le plages nommées dynamiques et la fonction INDIRECT qui permet de construire des formules en mode dynamique via le passage de certains de ces paramètres ci-dessous.

Enfin en ce qui concerne le code VBA il reste standard aux utilitaires que j'ai publié. Il présente de bonnes choses pour les internautes du Forum qui souhaiteraient avancer plus loin en VBA. Idem pour PowerQuery, une manière "de mettre le pied à l'étrier".


A propos de la fonction LAMBDA et fonctions avancées


1703542516172.png


Traduction de ces paramètres dans un tableau (pour les macros et powerquery) - Onglet [Params]
Extrait - ils sont repris dans un tableau de paramètres pilotés par les Macro via une classe dédiée. Voir un de post à ce propos.

1703542643585.png


Onglet [Source données] - extrait
Les informations sont sans aucune valeur fonctionnelle

Source
1703542820465.png


Transformation
1703542741758.png


Quelque soit le mode de traitement
1703542889357.png


Voici le résultat
1703542922491.png


RQ_MROMAIN
PowerQuery:
let

    //=================================================================================================
    // Auteur : Oguruma2D
    // Forum  : https://excel-downloads.com/
    // Objet  : Adaptation du code de mromain (XLD) afin que la requête soit dynamique
    //=================================================================================================

    // ---------------------------------------------------------------------------
    // Paramètres pour gérer la requête en fonction du contexte des données source
    // ---------------------------------------------------------------------------
    TbSource=getParameters("TB_PARAMS", "PARAM_TB_SOURCE"),
    ColonneTitre=getParameters("TB_PARAMS", "PARAM_COLONNE_TITRE"),
    LabelEtiquette=getParameters("TB_PARAMS", "PARAM_TITRE_ETIQUETTE"),
    LabelValeur=getParameters("TB_PARAMS", "PARAM_TITRE_VALEUR"),
    LabelEtiquetteDefault=getParameters("TB_PARAMS", "PARAM_DEFAULT_COLUMN_1"),
    LabelValeurDefault=getParameters("TB_PARAMS", "PARAM_DEFAULT_COLUMN_2"),
    Etiquette=if ColonneTitre = "OUI" then LabelEtiquette else LabelEtiquetteDefault,
    Valeur=if ColonneTitre = "OUI" then LabelValeur else LabelValeurDefault,

    //=================================================================================================
    // Auteur : mromain
    // Forum  : https://excel-downloads.com/
    // Objet  : Reprise du code en l'état avec remplacement par les paramètres en début de requête
    // Params : TbSource, Etiquette, Valeur
    //=================================================================================================
    Source = Excel.CurrentWorkbook(){[Name=TbSource]}[Content],
    RenameColumns = Table.RenameColumns(Source,{{Etiquette, "Name"}, {Valeur, "Value"}}),
    SplitTable = Table.Split(RenameColumns, List.Count(List.Distinct(RenameColumns[Name]))),
    ConvertToRecord = List.Transform(SplitTable, Record.FromTable),
    ToTable = Table.FromRecords(ConvertToRecord)
in
    ToTable

Requête d'importation
PowerQuery:
let

    //=================================================================================================
    // Auteur : Oguruma2D
    // Forum  : https://excel-downloads.com/
    // Objet  : Ceci fait suite au post à propos du dégroupage de lignes en colonnes
    //=================================================================================================

    //-------------------------------------------------------------------------------------------------
    // On récupère les paramètres du fichier source à importr
    // puis si ce fichier source comporte des titres de colonnes
    //-------------------------------------------------------------------------------------------------
    FichierSource=getParameters("TB_PARAMS", "PARAM_FICHIER_SOURCE"),
    ColonneTitre=getParameters("TB_PARAMS", "PARAM_COLONNE_TITRE"),
    Sep=getParameters("TB_PARAMS", "PARAM_SEPARATEUR"),

    Source = Csv.Document(File.Contents(FichierSource),[Delimiter=Sep, Columns=2, Encoding=65001, QuoteStyle=QuoteStyle.None]),
    Promote = if ColonneTitre ="OUI" then Table.PromoteHeaders(Source, [PromoteAllScalars=true]) else Source
in
    Promote

Requête pour le passage de paramètres à PowerQuery : getParameter
PowerQuery:
(pTable as text, pName as text) =>
 let
        Source = Excel.CurrentWorkbook(){[Name=pTable]}[Content],
        RowsParams = Table.SelectRows(Source, each ([PARAMETRE] = pName)),
        value = RowsParams{0}[VALEUR]
in
        value

Ici le post concernant le passage de paramètres à une requête PowerQuery

A propos du mode dynamique
Comme expliqué dans le poste initial il est possible de faire ce dégroupage par formule. Ceci a été traduit dans une macro ayant pour but de poser les formules de dégroupage puis de les transformer en valeurs afin de ne pas encombrer la feuille de calculs surtout en cas de forte volumétrie.

Extrait du code
Code:
    '--------------------------------------
    ' Formule pour les titres des colonnes
    '--------------------------------------
    Range(sADRESSE_COLONNE_TITRE_DYNAMIC).Activate
    Range(sADRESSE_COLONNE_TITRE_DYNAMIC).Formula2R1C1 = _
        "=" & sFORMULE_TITRE_COLONNE
 
    '----------------------------------------------------------------------------------
    ' Formule pour le dégroupage - contraint de la mettre en dur car erreur de compile
    ' en mode variable comme les titres des colonnes
    '-----------------------------------------------------------------------------------
    Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE).Activate
    Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE).Formula2R1C1 = _
        "=myDEGROUPE(NBR_ETIQUETTES_PAR_GROUPE,NUM_LIGNE_CIBLE_DONNEES,NUM_COLONNE_CIBLE_ETIQUETTE,ADRESSE_DEBUT_VALEUR_DYNAMIQUE)"

    '-----------------------------------------
    ' Recopie de la formule sur la 1ère ligne
    '-----------------------------------------
    Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE).Copy
    Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE & ":" & sADRESSE_DEGROUPAGE_FIN_COLONNE).PasteSpecial _
        Paste:=xlPasteFormulas, Operation:=xlNone, _
        SkipBlanks:=False, Transpose:=False
    
    '--------------------------------------------
    ' Recopie des formules sur toute la plage
    '--------------------------------------------
    Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE & ":" & sADRESSE_DEGROUPAGE_FIN_COLONNE).Copy
    Range(Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE & ":" & sADRESSE_DEGROUPAGE_FIN_COLONNE), sADRESSE_DEGROUPAGE_FIN_LIGNE).PasteSpecial _
        Paste:=xlPasteFormulas, Operation:=xlNone, _
        SkipBlanks:=False, Transpose:=False
 
    '---------------------------
    ' Activation des calculs
    '---------------------------
    Calculate

    '--------------------------------------
    ' Transforme les formules en valeurs
    '--------------------------------------
    Range(Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE & ":" & sADRESSE_DEGROUPAGE_FIN_COLONNE), sADRESSE_DEGROUPAGE_FIN_LIGNE).Copy
    Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE).PasteSpecial Paste:=xlPasteValues, _
        Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False

    Application.CutCopyMode = False

A propos du mode Macro
Deux versions :
1. Exploration et traitement des données directement sur les feuilles source et cible
2. Exploration et traitement des données via des tableaux en mémoire. Les données sources sont montées et le résultat de la ventilation est aussi déposé dans un tableau en mémoire. A l'issue le tableau en mémoire résultant est déposé sur la feuille

Extrait du code version 1
VB:
    '------------------------------------------------------------
    ' Parsing des données dans l'onglet source ligne/colonne
    '------------------------------------------------------------
    For lngIndexRow = LngIndexStartRow To lngMaxLoopRow
        ' On détermine les limites du parsing en colonne
        lngMaxLoopCol = LngIndexStartColumn + iNbItem - 1
        ' dispatching en colonne
        For lngIndexColumn = LngIndexStartColumn To lngMaxLoopCol
            ' on se déplace dans le tableau
            lngParse = lngParse + 1
            ' On va se décaler d'une cellule pour récupérer la valeur de l'item et affectation
            wkMacro.Cells(lngIndexRow, lngIndexColumn).Value = DataSource.Cells(lngParse, 1).Offset(0, 1)
        Next lngIndexColumn
        ' et traitement du bloc suivant
    Next lngIndexRow

Extrait du code version 2
Code:
'-------------------------------
    ' Init du parsing des données
    '------------------------------
    lngParse = 0
    lngMaxLoopRow = (LngIndexStartRow + (DataSource.Rows.Count / iNbItem))
 
    '-------------------------------------------------------------------------
    '               Préparation du travail en mémoire
    '-------------------------------------------------------------------------
    ' Initialisation des tableaux de récupération des étiquettes et valeurs
    ' Ici via cette méthode le degroupage est effectué dans un tableau
    ' A l'issue ce tableau sera déposé sur la cellule destination
    '-------------------------------------------------------------------------
 
    '-------------------------------------------------------------------------
    ' Nbre de lignes max à traiter
    '-------------------------------------------------------------------------
    lngEndRow = wkSource.Range(sADRESSE_DEBUT_ETIQUETTE).End(xlDown).Row
 
    '---------------------------------------------------------------------------
    ' On initialise le tableau qui va recevoir les données en mémoire
    '---------------------------------------------------------------------------
    ReDim vData(1 To lngMaxLoopRow - 1, 1 To CInt(sNBR_ETIQUETTES_PAR_GROUPE))
 
    '-----------------------------------------------------------------------------
    ' Ce tableau contient les valeurs à traiter
    '-----------------------------------------------------------------------------
    vValues = wkSource.Range(sADRESSE_DEBUT_ETIQUETTE).Resize(lngEndRow, 2).Value
 
    '----------------------------------------------------------------------------
    ' Parsing du tableau qui contient les étiquettes à dégrouper
    '----------------------------------------------------------------------------
    For lngIndexRow = LngIndexStartRow To lngMaxLoopRow - 1
        ' On détermine les limites du parsing
        lngMaxLoopCol = LngIndexStartColumn + iNbItem - 1
        ' dispatching en colonne
        For lngIndexColumn = LngIndexStartColumn To lngMaxLoopCol
            ' on se déplace dans le tableau
            lngParse = lngParse + 1
            '-----------------------------------------------------------------------------------
            ' On va se décaler d'une cellule pour récupérer la valeur de l'item et affectation
            ' wkMacro.Cells(lngIndexRow, lngIndexColumn).Value = DataSource.Cells(lngParse, 1).Offset(0, 1)
            ' on balaye les données en mémoire via les tableaux initialisés au préalable
            '-----------------------------------------------------------------------------------
            vData(lngIndexRow - 1, lngIndexColumn) = vValues(lngParse, 2)
        Next lngIndexColumn
        ' et traitement du bloc suivant
    Next lngIndexRow
 
    '------------------------------------------------------------------------------
    ' On dépose le tableau résultat à la cellule cible de l'onglet Macro
    ' On taille la plage d'arrivée en fonction de la taille du tableau de données
    '------------------------------------------------------------------------------
    Set rOutputData = wkMacro.Range(sADRESSE_DEGROUPAGE_DEBUT_COLONNE).Resize(UBound(vData, 1), UBound(vData, 2))
 
    '----------------------
    ' dépot sur la feuille
    '----------------------
    rOutputData = vData
Auteur
Oguruma
Version
1.0