Power Query Simplifier/Universaliser l'import multiple de fichiers CSV

Staple1600

XLDnaute Barbatruc
Bonsoir le forum

Je cherche à simplifier l'import de CSV à partir d'un dossier donné.

Quand on utilise l'assistant de PowerQuery, il y a de nombreuses étapes (voir ci-dessous)
PQ_CSV_Capture.PNG


PowerQuery:
let
    Source = Folder.Files("C:\Users\STAPLE\Documents\PQ_CSV"),
    #"Fichiers masqués filtrés1" = Table.SelectRows(Source, each [Attributes]?[Hidden]? <> true),
    #"Appeler une fonction personnalisée1" = Table.AddColumn(#"Fichiers masqués filtrés1", "Transformer le fichier", each #"Transformer le fichier"([Content])),
    #"Colonnes renommées1" = Table.RenameColumns(#"Appeler une fonction personnalisée1", {"Name", "Source.Name"}),
    #"Autres colonnes supprimées1" = Table.SelectColumns(#"Colonnes renommées1", {"Source.Name", "Transformer le fichier"}),
    #"Colonne de tables développée1" = Table.ExpandTableColumn(#"Autres colonnes supprimées1", "Transformer le fichier", Table.ColumnNames(#"Transformer le fichier"(#"Exemple de fichier"))),
    #"Type modifié" = Table.TransformColumnTypes(#"Colonne de tables développée1",{{"Source.Name", type text}, {"ITEM_1", Int64.Type}, {"ITEM_2", Int64.Type}, {"ITEM_3", Int64.Type}, {"ITEM_4", Int64.Type}, {"ITEM_5", Int64.Type}, {"ITEM_6", Int64.Type}, {"ITEM_7", Int64.Type}, {"ITEM_8", Int64.Type}})
in
    #"Type modifié"
On peut faire plus simple et générique que Microsoft, non ?

Quelqu'un aurait-il un code M plus synthétique et universel(*) pour faire cette opération ?
(*) notamment ici #"Type modifié" : ne pas avoir à lister tous les noms des colonnes

PS: j'ai regardé sur le forum les discussions avec le préfixe PowerQuery, j'ai regardé quelques vidéos sur YT (mais c'est pas pratique) et enfin je n'ai pas solliciter ChatGPT, préférant mes frères humains (notamment ceux d'XLD) et aussi un peu en souvenir de Sarah Connor. ;)

NB: Il me semble que les étapes de Microsoft sont peu ou prou ce que montrent cette vidéo, non ?
https://www.youtube.com/watch?app=desktop&v=IsLB3XR9eno
 
Solution
Re,

@alexga78
j'utilise aussi Office 365

Les fichiers de test CSV sont issus d'Excel (Enregistrer sous -> CSV, séparateur point virgule)

Tu as essayé avec les fichiers contenu dans le zip du message#2 ?

Tu peux mettre ton code M complet, stp avec le let .... in
merci

Sinon tu vois comment simplifier le code "anglophone" ?

Re,
les fichiers testés sont ceux du zip.

un autre essai pour le nom des fichiers

PowerQuery:
let
    Source = Folder.Files("C:\Users\STAPLE\Documents\PQ_CSV"),
    Result = let x =  Table.SelectColumns(Table.AddColumn(Source, "Custom", each Table.PromoteHeaders(Csv.Document([Content],[Delimiter=";", Encoding=TextEncoding.Windows, QuoteStyle=QuoteStyle.None]))),{"Name","Custom"}) in Table.ExpandTableColumn(x,"Custom", List.Union(Table.TransformColumns(x, {"Custom", each...

Staple1600

XLDnaute Barbatruc
Re

J'ai voulu faire ceci
Code:
let
    F_PATH = Excel.CurrentWorkbook(){[Name="CSV_PATH"]}[Content],
    Source = Folder.Files(F_PATH),
    FichiersCSV = Table.SelectRows(Source, each [Extension]=".csv"),
    Result = let x =  Table.SelectColumns(Table.AddColumn(FichiersCSV, "Custom", each Table.PromoteHeaders(Csv.Document([Content],[Delimiter=";", Encoding=TextEncoding.Windows, QuoteStyle=QuoteStyle.None]))),{"Name","Custom"}) in Table.ExpandTableColumn(x,"Custom", List.Union(Table.TransformColumns(x, {"Custom", each Table.ColumnNames(_)})[Custom]))
in
    Result
Avec dans ma plage nommée CSV_PATH
C:\Users\STAPLE\Documents\PQ_CSV
ou
C:\Users\STAPLE\Documents\PQ_CSV\

J'obtiens cette erreur
Expression.Error : Désolé... Nous n'avons pas pu convertir une valeur de type Table en type Text.
Détails :
Value=

Type=[Type]
Qu'est-ce que j'ai oublié ?

PS: ma version de PQ
2.127.277.0 64 bits
 

Staple1600

XLDnaute Barbatruc
Re

@alexga78 ,@Cousinhub
PQ est assez intelligent où ainsi réduit je prends des risques ?
PowerQuery:
let
F_PATH= Excel.CurrentWorkbook(){[Name="CSV_PATH"]}[Content]{0}[Column1],
Source=Folder.Files(F_PATH),
Result = let x =  Table.SelectColumns(Table.AddColumn(Source, "Custom", each Table.PromoteHeaders(Csv.Document([Content],[Delimiter=";"]))),{"Name","Custom"}) in Table.ExpandTableColumn(x,"Custom", List.Union(Table.TransformColumns(x, {"Custom", each Table.ColumnNames(_)})[Custom]))
in
Result
Question subsidiaire:
En code M, on ne peut pas utiliser _ pour rendre de code plus lisible
(quand les lignes de code sont longues)

PS: Avis aux autres PQristes émérites du forum
Pour le fun et par curiosité, n'hésitez pas à soumettre d'autres syntaxe en code M pour obtenir le même résultat qu'@alexga78 que je remercie de nouveau

J'ai besoin de lire du code M à profusion dans mon browser pour le plaisir
(et pour éviter les tohubohu à venir (européennes, jeux olympiques, élections américaines)

;)
 

Cousinhub

XLDnaute Barbatruc
Hi,
Nul besoin de _, la syntaxe de PQ permet des retours à la ligne, tabulations, espaces
PowerQuery:
let
    F_PATH = Excel.CurrentWorkbook(){[Name="CSV_PATH"]}[Content]{0}[Column1],
    Source = Folder.Files(F_PATH),
    FichiersCSV = Table.SelectRows(Source, each [Extension]=".csv"),
    Result =    let x =  Table.SelectColumns(Table.AddColumn(FichiersCSV, "Custom", each Table.PromoteHeaders(Csv.Document([Content],
                    [Delimiter=";", Encoding=TextEncoding.Windows, QuoteStyle=QuoteStyle.None]))),{"Name","Custom"})
                in Table.ExpandTableColumn(x,"Custom", List.Union(Table.TransformColumns(x, {"Custom", each Table.ColumnNames(_)})[Custom]))
in
    Result
 

alexga78

XLDnaute Occasionnel
Re JM, Bonjour CousinHub, le forum,

pour le retour à la ligne et rendre le code plus lisible - CTRL + Entrée.
une autre proposition alors :)


PowerQuery:
let
Source = Table.SelectColumns(Table.AddColumn(Table.SelectRows(Folder.Files(Table.ToList(Excel.CurrentWorkbook(){[Name="CSV_PATH"]}[Content]){0}),
each [Extension] = ".csv"), "Custom", each Table.PromoteHeaders(Csv.Document([Content],null,";"))),{"Name","Custom"}),
Result = Table.ExpandTableColumn(Source, "Custom", List.Union(List.Accumulate({0..Table.RowCount(Source)-1}, {}, (s,c)=> s & {Table.ColumnNames(Source[Custom]{c})})))
in
Result

Bon WE à tous.
 

Staple1600

XLDnaute Barbatruc
Re

@alexga78
Je chausse les lunettes et sors le Doliprane pour étudier ta nouvelle proposition
C'est du costaud ;)

Moi, en me basant sur tes syntaxes, j'en étais à
PowerQuery:
let
F_PATH= Excel.CurrentWorkbook(){[Name="CSV_PATH"]}[Content]{0}[Column1],
Colonnes = Table.SelectColumns(Table.AddColumn(Folder.Files(F_PATH), "Custom", each Table.PromoteHeaders(Csv.Document([Content], [Delimiter=";"]))),{"Name","Custom"}),
Final = Table.ExpandTableColumn(Colonnes, "Custom", {"ITEM_1", "ITEM_2", "ITEM_3", "ITEM_4", "ITEM_5", "ITEM_6", "ITEM_7", "ITEM_8"}, {"ITEM_1", "ITEM_2", "ITEM_3", "ITEM_4", "ITEM_5", "ITEM_6", "ITEM_7", "ITEM_8"})
in
Final
L'étape Final résulte de l'assistant de PQ

On ne peut pas lui lire dire simplement ?
Table.ExpandTableColumn(Colonnes,"Custom", Toutes les colonnes)
(Sans devoir avoir une matrice(*) qui contient les noms des entêtes des CSV)
(*): c'est bien une matrice, non ?

@Cousinhub
Merci pour la piqûre de rappel
 

Staple1600

XLDnaute Barbatruc
Re

@alexga78
Avec ceci, tu m'as perdu ;)
List.Union(List.Accumulate({0..Table.RowCount(Source)-1}, {}, (s,c)=> s & {Table.ColumnNames(Source[Custom]{c})}))
Et il est trop tôt pour prendre un second Doliprane

En attendant, comme je ferais en sorte qu'il n'y ait que des CSV dans le dossier, j'ai modifié ton dernier code ainsi
Code:
let
Source = Table.SelectColumns(Table.AddColumn(Folder.Files(Table.ToList(Excel.CurrentWorkbook(){[Name="CSV_PATH"]}[Content]){0}), "Custom", each Table.PromoteHeaders(Csv.Document([Content],null,";"))),{"Name","Custom"}),
Result = Table.ExpandTableColumn(Source, "Custom", List.Union(List.Accumulate({0..Table.RowCount(Source)-1}, {}, (s,c)=> s & {Table.ColumnNames(Source[Custom]{c})})))
in
Result
Et avec ceci, {}, (s,c)=> s , j'ai renversé ma tasse de thé ;)

PS: Si jamais un jour de pluie, tu t'ennuies, tu peux revenir dans ce fil et ajouter des commentaires explicatifs de ta syntaxe M, cela évitera que j'enrichisse trop BigPharma ;)
 

Staple1600

XLDnaute Barbatruc
Re

Donc pas de moyen simple de passer de
Code:
Table.SelectColumns(Table.AddColumn(Folder.Files(F_PATH), "Custom", each Table.PromoteHeaders(Csv.Document([Content], [Delimiter=";"]))),{"Name","Custom"})
A la dernière étape ?

Il faut en passer par ta syntaxe ciselée aux petits oignons ?

Syntaxe que j'ai du mal à appréhender avec mes neurones déformés par l'usage du VBA (depuis Excel 97)
;)

EDITION: J'avais pas vu ton code @Cousinhub
je teste de suite
 

Staple1600

XLDnaute Barbatruc
Re

@Cousinhub
Cela semble faire le job.
Merci ;)
PowerQuery:
let
F_PATH= Excel.CurrentWorkbook(){[Name="CSV_PATH"]}[Content]{0}[Column1],
Colonnes = Table.SelectColumns(Table.AddColumn(Folder.Files(F_PATH), "Custom", each Table.PromoteHeaders(Csv.Document([Content], [Delimiter=";"]))),{"Name","Custom"}),
Final = Table.ExpandTableColumn(Colonnes, "Custom", List.Distinct(List.Combine(List.Transform(Colonnes[Custom], each Table.ColumnNames(_)))))
in
Final
Et avec ce code, je sollicite moins mes vieux neurones

Question subsidiaire:
Pourquoi l'assistant PQ ne pond pas un code M de ce genre quand on clique sur Développer ?
(celui proposé par CousinHub
Dev_PQ.PNG
 

alexga78

XLDnaute Occasionnel
List.accumulate est LA fonction magique de PQ pour boucler.

Synthaxe : List.Accumulate(list as list, seed as any, accumulator as function) as any

PowerQuery:
List.Union(List.Accumulate(
{0..Table.RowCount(Source)-1}, // liste à accumuler – l’indice de chaque ligne de l’étape précédente
{}, // la seed : une liste vide car nous voulons une liste des noms de colonnes
(s,c)=> s & {Table.ColumnNames(Source[Custom]{c})}))

s pour state – état initial qui va devenir le current (c) à la première boucle puis state de la seconde boucle et ainsi de suite.

Enfin List.Union pour éliminer les doublons.

Je ne sais pas si c’est plus clair…
 

Cousinhub

XLDnaute Barbatruc
Re-,
Tout comme l'enregistreur VBA enregistre ce que tu fais, le code généré reste quand même sujet à moult modifications, améliorations?...
PQ, c'est tout pareil, il enregistre ce que tu fais, la plupart du temps, cela suffit, mais si tu veux "optimiser", "prévoir", ajouter des opérations non prévues par les rubans de l'éditeur, il faut alors programmer.
 

Staple1600

XLDnaute Barbatruc
Re

@Cousinhub
ajouter des opérations non prévues par les rubans de l'éditeur, il faut alors programmer.
Et c'est là, que le bât blesse, car la syntaxe M est bien différente de VBA
et mobiliser mes derniers neurones logés dans une boite crânienne forgée au XXième siècle pour tout réapprendre, c'est pas finger in the noze ;)

@alexga78
Merci pour les explications sur la fonction magique de PQ ;)
PS: Tu es un utilisateur chevronné de PQ, non ?
C'est pour mon carnet à spirales où je note les pseudos des membres du forum qui maitrisent PQ en plus d'être sympathique
@Cousinhub est déjà dessus
 

Statistiques des forums

Discussions
312 393
Messages
2 087 975
Membres
103 689
dernier inscrit
nouicer