[[20220822135118]] 『パワークエリにて長大な列を2列ごとにマージしてax(テクマク・マヤコン ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『パワークエリにて長大な列を2列ごとにマージしていきたい』(テクマク・マヤコン )

お世話になります。

現在パワークエリにてシフト表を集計し、システム用のレイアウトに整形しています。

そこでデータを2列ごとにマージしていく必要があるのですが、データが膨大で150列程まで増えることが分かりました。

この2列ごとの列のマージを一括もしくは簡単に繰り返しさせるなどはできないものでしょうか?

お知恵をお借りしたく、何卒よろしくお願いいたします。

< 使用 Excel:Office365、使用 OS:Windows10 >


まずはピボット解除してはどうでしょう

(マナ) 2022/08/22(月) 14:51


 雰囲気だけです
 なんか繰り返しが最後までいかない感じが謎?? どこか間違ってます。
 let
    ソース = Excel.CurrentWorkbook(){[Name="テーブル1"]}[Content],
    変更された型 = Table.TransformColumnTypes(ソース,{{"a", type text}, {"b", type text}, {"c", type text}, {"d", type text}, {"e", type text}, {"f", type text}, {"g", type text}, {"h", type text}}),
    カスタム1 = List.Generate(()=>[列リスト=Table.ColumnNames(変更された型),列結合したテーブル=変更された型],
                                  each List.Count([列リスト])>=2,
                                  each [列リスト=List.RemoveLastN([列リスト],2),列結合したテーブル=Table.CombineColumns([列結合したテーブル],List.LastN([列リスト],2),Combiner.CombineTextByDelimiter("", QuoteStyle.None),Text.Combine(List.LastN([列リスト],2),"&"))],
                                  each [列結合したテーブル] ),
    カスタム2 = List.LastN(カスタム1,1){0}
 in
    カスタム2
(´・ω・`) 2022/08/22(月) 16:52

確かに最後もう1回removeしてくれませんね。

 let
    ソース = {1..7},
    カスタム1 = List.Generate(
        ()=>[x=ソース],
        each List.Count([x])>=2,
        each [x=List.RemoveLastN([x],2)],
        each [x])
 in
    カスタム1

構文は間違っていないと思うのですが…
下記は、期待通りになるので。

 let
    ソース = {1..7},
    カスタム1 = List.Generate(
        ()=>[n=0,x={}],
         each [n]<=List.Count(ソース),
        each [n=[n]+2, x=List.Range(ソース,[n],2)],
        each [x])
 in
    カスタム1

(マナ) 2022/08/22(月) 21:50


RemoveFirstNでもだめでした。

(マナ) 2022/08/22(月) 21:55


質問者さんへ

こんな操作の流れで、たぶんできます。

 ・ピボット解除
 ・インデックス列の追加
 ・除算(整数)
 ・グループ化
 ・カスタム列の追加(Text.Combineで、文字列結合)
 ・ピボット

簡単なサンプルデータ(列は数列で結構)を提示してもらえると
もっと具体的に回答できます。

(マナ) 2022/08/22(月) 22:06


  こんな感じでいかがでしょうか。

 let
     tbl = Excel.CurrentWorkbook(){[Name="テーブル1"]}[Content],
     namelist=Table.ColumnNames(tbl),
     maxn = Table.ColumnCount(tbl),

     // 再帰関数
     fn列マージ = (parTable as table,n as number) as table=>
          if n > maxn then 
              parTable
          else
              let
                 col1 = namelist{n-1},
                 col2 = namelist{n},
                 wtbl = Table.CombineColumns(parTable,{col1,col2},Combiner.CombineTextByDelimiter(" ", QuoteStyle.None),
                                             "item" & Text.From((n+1)/2)),
                 nextTable = @fn列マージ(wtbl,n+2)
              in
                 nextTable,

     //列マージの実行
     tbl2 = fn列マージ(tbl, 1)   
 in
     tbl2

(gamma) 2022/08/23(火) 00:32


 いいですね こういうの好きです
(´・ω・`) 2022/08/23(火) 07:02

 できたできた
 let
    ソース = Excel.CurrentWorkbook(){[Name="テーブル1"]}[Content],
    型変更の繰り返し = List.Generate(()=>[T=ソース,L=Table.ColumnNames(ソース),n=Table.ColumnCount(ソース),i=0],                // 初期値
                                    each [i]<=[n],                                                                           // 繰返し継続条件 
                                    each [T=Table.TransformColumnTypes([T],{{L{[i]}, type text}}),i=[i]+1,L=[L],n=[n]],      // 次の値
                                    each [T]),                                                                               // リストの値
    変更された型 = List.LastN(型変更の繰り返し,1){0},
    カスタム1 = List.Generate(()=>[T=変更された型,L=Table.ColumnNames(ソース),n=Table.ColumnCount(変更された型),i=Table.ColumnCount(変更された型)],                                              // 初期値
                                    each [i]>=0,                                                                                                                                             // 繰返し継続条件 
                                    each [T=Table.CombineColumns([T],{L{[i]-2}, L{[i]-1}},Combiner.CombineTextByDelimiter("", QuoteStyle.None),L{[i]-2}&L{[i]-1}),i=[i]-2,L=[L],n=[n]],      // 次の値
                                    each [n=[n],i=[i],T=[T]]),
    カスタム2 = List.LastN(カスタム1,1){0}[T]
 in
    カスタム2
(´・ω・`) 2022/08/23(火) 11:43

 列数不定、任意の列名のすべての列の型を文字列にするには、

    変更された型 = Table.TransformColumnTypes(ソース,List.Zip({Table.ColumnNames(ソース),List.Repeat({type text},Table.ColumnCount(ソース))}))

 のようにすればいいみたいです
(´・ω・`) 2022/08/23(火) 12:28

限界です。Remove系はやはりだめでした。
List.Rangeならできるのですが…
(´・ω・`)さんのと考え方は同じです。

 let
    ソース = Excel.CurrentWorkbook(){[Name="テーブル1"]}[Content],
    変更された型 = Table.TransformColumnTypes(ソース,
        List.Transform(Table.ColumnNames(ソース), each {_, type text})),
    見出し = Table.ColumnNames(変更された型),
    カスタム1 = List.Generate(
        ()=>[t=変更された型,n=0],
         each [n]<=List.Count(見出し),
        each [
            n=[n]+2, x=List.Range(見出し,[n],2),L=Text.Combine(x,"&"),
            t=Table.CombineColumns([t],x,Combiner.CombineTextByDelimiter("", QuoteStyle.None),L)
        ],
        each [t])
  in
    カスタム1

(マナ) 2022/08/23(火) 13:07


操作だけでする場合、1つ手順がぬけていました。
最初に、nullを空白に置換する必要がります。
元のテーブルで、全セルがデータで埋まっていれば、この操作が必要ありません。

で、一連の操作を実行すると、下記のようなコードが自動記録されますが
この置換操作に該当する部分だけは、編集する必要があります。
表の見出しが変わっても対応できるようにするためです。

 >   置き換えられた値 = Table.ReplaceValue(ソース,null,"",Replacer.ReplaceValue,{"a", "b", "c", "d", "e", "f"}),

 {"a", "b", "c", "d", "e", "f"}
  ↓

  Table.ColumnNames(ソース)

その他の行は、そのまま使用可能です。

 '-----記録されたコード(詳細エディター)

 let
    ソース = Excel.CurrentWorkbook(){[Name="テーブル2"]}[Content],
    置き換えられた値 = Table.ReplaceValue(ソース,null,"",Replacer.ReplaceValue,{"a", "b", "c", "d", "e", "f"}),
    追加されたインデックス = Table.AddIndexColumn(置き換えられた値, "インデックス", 0, 1, Int64.Type),
    ピボット解除された他の列 = Table.UnpivotOtherColumns(追加されたインデックス, {"インデックス"}, "属性", "値"),
    変更された型 = Table.TransformColumnTypes(ピボット解除された他の列,{{"値", type text}}),
    追加されたインデックス1 = Table.AddIndexColumn(変更された型, "インデックス.1", 0, 1, Int64.Type),
    挿入された整数除算 = Table.AddColumn(追加されたインデックス1, "整数除算", each Number.IntegerDivide([インデックス.1], 2), Int64.Type),
    グループ化された行 = Table.Group(挿入された整数除算, {"インデックス", "整数除算"}, {{"group", each _, type table [インデックス=number, 属性=text, 値=text, インデックス.1=number, 整数除算=number]}}),
    追加されたカスタム = Table.AddColumn(グループ化された行, "属性", each Text.Combine([group][属性],"&")),
    追加されたカスタム1 = Table.AddColumn(追加されたカスタム, "値", each Text.Combine([group][値])),
    削除された他の列 = Table.SelectColumns(追加されたカスタム1,{"インデックス", "属性", "値"}),
    ピボットされた列 = Table.Pivot(削除された他の列, List.Distinct(削除された他の列[属性]), "属性", "値"),
    削除された列 = Table.RemoveColumns(ピボットされた列,{"インデックス"})
 in
    削除された列

詳細テディターを開いて、↑のコードで上書きしてください。
で、適用されたステップを順に追いかけて、どのような流れか確認して
わからないところは質問してください。

(マナ) 2022/08/23(火) 15:42


テーブルデータをPoqwer Queryエディターに取得した段階で
通常、2ステップ目に「変更された型」が追加されていると思います。

これは不要なので、一番最初に削除してください。
型の変更は、ピボット解除してから行います。

(マナ) 2022/08/23(火) 15:52


みなさま、ありがとうございます!

なんだかもう理解できない高次元の話でついていけていないのですが、まずイチから読んで実行してみます。

絶対分からないところが出てくると思いますので、また質問させていただくことになります。
引き続きよろしくお願いいたします!
(テクマク・マヤコン ) 2022/08/23(火) 17:19


 ´・ω・` さん、マナさん、また材料提示いただいたテクマク・マヤコン さん、
 ありがとうございました。

 PowerQueryはいつまでも慣れませんね。お二方の回答を学習させていただきます。

 質問者さん、私の回答は全スキップで結構ですよ。

 (以下、余談)
 「VBAは会社方針で禁止されているので、PowerQueryを使うよう学習しています」
 という投稿がありましたが、それって、何かおかしくないですか?という印象です。
 はやりのDXという考え方に抵触しないのか、と思ってしまいます。

 まあ、余り属人化しないようにしようとすると、
 自前でプログラミング?せず、操作の記録に留める、というのがよいのでしょうか。
 この場合は、予めワークシート上で文字列連結をしてしまう、というのも一法かもしれません。

(gamma) 2022/08/23(火) 21:22


 gammaさん、ありがとうございます。
もともと再帰は苦手なので、いまだに自力ではかけません。
提示されたものをみると理解はできるのですが…。
@マークなんて、すっかり忘れていました。
以前教えていただいた参考サイトを読み返して思い出しました。

(マナ) 2022/08/25(木) 20:24


質問者さん、苦労しているのかしら。
わからなければ、遠慮なく、確認してください。
まだまだ少ないPower Query関連は、質問してくれるだけでありがたいです。

検索しても、List.Generateで、RemoveLastNが、うまくいかない理由がわからない。
練習兼ねて、γさんの再帰で、List.RemoveLastNがどうなるか確認。問題なし。
慣れれば、List.Generateより簡単な気がしてきました。

 let
     ソース = {1..5},
     fn1 = (x as list) as list=>
          if List.Count(x) < 2 then 
              x
          else
              let
                  y = List.RemoveLastN(x, 2),
                  z = @fn1(y)
              in 
                  z               
 in             
     fn1(ソース)

(マナ) 2022/08/25(木) 21:37


 コメント痛み入ります。

 | 確かに最後もう1回removeしてくれませんね。
 |  let
 |     ソース = {1..7},
 |     カスタム1 = List.Generate(
 |         ()=>[x=ソース],
 |         each List.Count([x])>=2,
 |         each [x=List.RemoveLastN([x],2)],
 |         each [x])
 |  in
 |     カスタム1
 この件ですが、
 condition は nextするかどうかの条件ではなく、
 nextで算定した結果が適格かどうかを調べるものなので、
 {1..3}から取り出した{1}は条件を満たさないので、
 Listの要素が追加されないのだと思います。
(gamma) 2022/08/26(金) 10:02

確認しました。
継続条件について完全に誤解していました。
大いなる収穫です。スッキリしました。
今回もありがとうございました。

(マナ) 2022/08/26(金) 12:31


 私もようやく分かりました
 ありがとうございました
 質問者さんがこないので、保守あげ
(´・ω・`) 2022/08/29(月) 09:05

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.