パワークエリ備忘録13(数字全角→半角 年月日作成 詳細エディター(if文)など)

<前置き>
こちらは素人です。
エクセル2016でパワークエリ、ピボットテーブルを使います。
office2016スタンダードなので、パワーピボットタブ出ません。
(「開発」タブのCOMアドインにパワーピボットがない)

 

<参考>
今回はいろんなHPを参考にしました。感謝。
Power Queryでlet式を使用する方法(プログラミング日記)
Power Query で 全角数字 から 半角数字 に変換するには(Qiita)
Power BIで、ある列に特定の文字列が含まれているか否かの情報を、別の列に記録する方法(Qiita)


<やったこと(パワークエリで年月日などを作成(if文や詳細エディタ(let in )など使用して))>

 

準備:
下記の感じのテーブルを準備
(この表自体も、事前に、元は、横持ちデータ(マトリックス)になっているものをパワークエリで、縦持ちデータにしています。データモデルに追加しています。)


(行ラベルずれてます)
職名1    職名2    名前    列1    詳細1    詳細2    属性  値
バイト職員    A1    山川    報酬    2450        5月    29400
バイト職員    A1    山川    報酬    2450        6月    66150
バイト職員    A1    山川    報酬    2450        7月    44100
バイト職員    A1    山川    報酬    2450        9月    66150
バイト職員    A1    山川    報酬    2450        10月    58800
バイト職員    A1    山川    報酬    2450        11月    66150
バイト職員    A1    山川    報酬    2450        12月    51450
バイト職員    A1    山川    報酬    2450        1月    58800
バイト職員    A1    山川    報酬    2450        2月    58800
バイト職員    A1    山川    報酬    2450        3月    51450
バイト職員    A1    海山    報酬    2450        5月    53900
バイト職員    A1    海山    報酬    2450        6月    63700
バイト職員    A1    海山    報酬    2450        7月    53900
バイト職員    A1    海山    報酬    2450        9月    63700


(注:いろんなよく分からない列があります。「値」が報酬等の合計。この列を値として使います。)
(注:「属性」は5月などだけでなく6月期末などの文字もあります。)
(注:「期末」はボーナスのこと。)


失敗:
上記をピボットテーブルにしようとすると、列が「月日順」に並びません。

    列ラベル                                                        
行ラベル    10月    11月    12月    12月期末    1月    2月    3月    4月    5月    
保険料                                                            
A1                                                            
山川                                                            
海山                                                            
BB1                                                            
大山                                                            
通勤手当                                                            
BB1                                                            
大山                                                            
報酬                                                            
A1                                                            
山川                                                            
海山                                                            
BB1                                                            
大山                                                            
総計                                                            

(注:「期末」はボーナスのこと。)

4月から並んで欲しい。

 


考え:
ここで、元データに戻って月日を直すのは面倒・・・。
(どっちが面倒かは分からないが、後戻りして、元データを直すのはパワークエリの意味がない。)


<作業>
(1)

属性が、

3月
4月
6月期末

などになっているので、パワークエリで、列の追加-抽出-区切り前のテキストで「月」で、全角数字を抽出しました。

(行ラベルずれてます)
職名1    職名2    名前    列1    詳細1    詳細2    属性    値    月(全角)
バイト職員    A1    山川    報酬    2450        5月    29400    5
バイト職員    A1    山川    報酬    2450        6月    66150    6
バイト職員    A1    山川    報酬    2450        7月    44100    7
バイト職員    A1    山川    報酬    2450        9月    66150    9


(2)
ここで、全角数字を半角数字に変換する必要がありますが、パワークエリにはないそうです。


そこで「Power Query で 全角数字 から 半角数字 に変換するには」という記事を参照しました。
詳しいことは省略しますが、いろんなやり方が書いてある。
その中で、一番簡単な全角数字を半角数字にしていくことにしました。Table.ReplaceValue

 

************************************************************
(上記記事より一部コピーしました。許可欲しいですm(_ _)mが、取り方分からんので少し変えました。
まあ、「値の置き換え」と同じことかな)

let
    ソース = サンプル,
    置き換えられた値 = Table.ReplaceValue(ソース,"0","0",Replacer.ReplaceText,{"全角数字"}),
    置き換えられた値1 = Table.ReplaceValue(置き換えられた値,"1","1",Replacer.ReplaceText,{"全角数字"}),
    置き換えられた値3 = Table.ReplaceValue(置き換えられた値2,"3","3",Replacer.ReplaceText,{"全角数字"}),
    置き換えられた値4 = Table.ReplaceValue(置き換えられた値3,"4","4",Replacer.ReplaceText,{"全角数字"}),
    置き換えられた値5 = Table.ReplaceValue(置き換えられた値4,"5","5",Replacer.ReplaceText,{"全角数字"}),
    置き換えられた値6 = Table.ReplaceValue(置き換えられた値5,"6","6",Replacer.ReplaceText,{"全角数字"}),
    置き換えられた値7 = Table.ReplaceValue(置き換えられた値6,"7","7",Replacer.ReplaceText,{"全角数字"}),
    置き換えられた値8 = Table.ReplaceValue(置き換えられた値7,"8","8",Replacer.ReplaceText,{"全角数字"}),
    置き換えられた値9 = Table.ReplaceValue(置き換えられた値8,"9","9",Replacer.ReplaceText,{"全角数字"})
    
in
    置き換えられた値9
***********************************************************

意味は分かるけど・・・、
「これをどこに作成すればいいの?」「let inって何?」と疑問になり(初心者)、
「Power Queryでlet式を使用する方法」(プログラミング日記)というHPを参照しました。

見てみると、表示-詳細エディタを開けばよさそう・・・。
****************************************
let
    ソース = Excel.CurrentWorkbook(){[Name="テーブル5"]}[Content],
    変更された型 = Table.TransformColumnTypes(ソース,{{"職名1", type text}, {"職名2", type text}, {"名前", type text}, {"列1", type text}, {"詳細1", type any}, {"詳細2", type any}, {"4月", Int64.Type}, {"5月", Int64.Type}, {"6月", Int64.Type}, {"6月期末", Int64.Type}, {"7月", Int64.Type}, {"8月", Int64.Type}, {"9月", Int64.Type}, {"10月", Int64.Type}, {"11月", Int64.Type}, {"12月期末", Int64.Type}, {"12月", Int64.Type}, {"1月", Int64.Type}, {"2月", Int64.Type}, {"3月", Int64.Type}, {"合計", type any}, {"科目", type text}}),
    フィルターされた行 = Table.SelectRows(変更された型, each ([職名2] = "A1" or [職名2] = "BB1") and ([詳細1] <> "勤務日数" and [詳細1] <> "勤務時間")),
    置き換えられた値 = Table.ReplaceValue(フィルターされた行,null,0,Replacer.ReplaceValue,{"4月"}),
    置き換えられた値1 = Table.ReplaceValue(置き換えられた値,null,0,Replacer.ReplaceValue,{"10月", "11月", "12月期末", "12月", "1月", "2月", "3月"}),
    置き換えられた値2 = Table.ReplaceValue(置き換えられた値1,null,0,Replacer.ReplaceValue,{"4月", "5月", "6月", "6月期末", "7月", "8月", "9月"}),
    削除された列 = Table.RemoveColumns(置き換えられた値2,{"科目", "合計"}),
    選択した列のみをピボット解除しました = Table.Unpivot(削除された列, {"4月", "5月", "6月", "6月期末", "7月", "8月", "9月", "10月", "11月", "12月期末", "12月", "1月", "2月", "3月"}, "属性", "値"),
    区切り記号の前に挿入されたテキスト = Table.AddColumn(選択した列のみをピボット解除しました, "区切り記号の前のテキスト", each Text.BeforeDelimiter([属性], "月"), type text),
    #"名前が変更された列 " = Table.RenameColumns(区切り記号の前に挿入されたテキスト,{{"区切り記号の前のテキスト", "月(全角)"}})
in
    #"名前が変更された列 "
************************************

自分のはこんな感じでした。
これは、全部のステップの記録のようです。(初心者)
letにプログラム(M言語)が記載されていて、inが最終出力の状態っぽい。
「ステップで作るより、この詳細エディタで書き込んだ方が楽っぽい」と気づきました。


ここで試行錯誤して、下記の形にしました。
(事前にステップでカスタム列を追加しています(仮に=月(全角)を参照するようにしています)。そのカスタム列に続くように直していきます。)
************************************************
let
    ソース = Excel.CurrentWorkbook(){[Name="テーブル5"]}[Content],
    変更された型 = Table.TransformColumnTypes(ソース,{{"職名1", type text}, {"職名2", type text}, {"名前", type text}, {"列1", type text}, {"詳細1", type any}, {"詳細2", type any}, {"4月", Int64.Type}, {"5月", Int64.Type}, {"6月", Int64.Type}, {"6月期末", Int64.Type}, {"7月", Int64.Type}, {"8月", Int64.Type}, {"9月", Int64.Type}, {"10月", Int64.Type}, {"11月", Int64.Type}, {"12月期末", Int64.Type}, {"12月", Int64.Type}, {"1月", Int64.Type}, {"2月", Int64.Type}, {"3月", Int64.Type}, {"合計", type any}, {"科目", type text}}),
    フィルターされた行 = Table.SelectRows(変更された型, each ([職名2] = "A1" or [職名2] = "BB1") and ([詳細1] <> "勤務日数" and [詳細1] <> "勤務時間")),
    置き換えられた値 = Table.ReplaceValue(フィルターされた行,null,0,Replacer.ReplaceValue,{"4月"}),
    置き換えられた値1 = Table.ReplaceValue(置き換えられた値,null,0,Replacer.ReplaceValue,{"10月", "11月", "12月期末", "12月", "1月", "2月", "3月"}),
    置き換えられた値2 = Table.ReplaceValue(置き換えられた値1,null,0,Replacer.ReplaceValue,{"4月", "5月", "6月", "6月期末", "7月", "8月", "9月"}),
    削除された列 = Table.RemoveColumns(置き換えられた値2,{"科目", "合計"}),
    選択した列のみをピボット解除しました = Table.Unpivot(削除された列, {"4月", "5月", "6月", "6月期末", "7月", "8月", "9月", "10月", "11月", "12月期末", "12月", "1月", "2月", "3月"}, "属性", "値"),
    区切り記号の前に挿入されたテキスト = Table.AddColumn(選択した列のみをピボット解除しました, "区切り記号の前のテキスト", each Text.BeforeDelimiter([属性], "月"), type text),
    #"名前が変更された列 " = Table.RenameColumns(区切り記号の前に挿入されたテキスト,{{"区切り記号の前のテキスト", "月(全角)"}}),
    追加されたカスタム = Table.AddColumn(#"名前が変更された列 ", "カスタム", each [#"月(全角)"]),

 

//新しいステップ名を付ける。直前のステップ名を使用する。カンマに注意

 

    置き換えられた値3 = Table.ReplaceValue(追加されたカスタム,"0","0",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値4 = Table.ReplaceValue(置き換えられた値3,"1","1",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値5 = Table.ReplaceValue(置き換えられた値4,"2","2",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値6 = Table.ReplaceValue(置き換えられた値5,"3","3",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値7 = Table.ReplaceValue(置き換えられた値6,"4","4",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値8 = Table.ReplaceValue(置き換えられた値7,"5","5",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値9 = Table.ReplaceValue(置き換えられた値8,"6","6",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値10 = Table.ReplaceValue(置き換えられた値9,"7","7",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値11 = Table.ReplaceValue(置き換えられた値10,"8","8",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値12 = Table.ReplaceValue(置き換えられた値11,"9","9",Replacer.ReplaceText,{"カスタム"})

in


//最後のステップ名に変える
    置き換えられた値12
*************************************************

(注:「//」はコメントブロックです。(気になったことをメモしています。閉じて読み込んだり保存しないと消えちゃうよ)
(注:コメントブロックは、/*  */も使えます。)

コメントブロックに書きましたが、詳細エディタで書くときは、
let部分は、新しいステップ名を付ける。直前のステップ名を使用する。カンマに注意(最後は不要)
in部分は、最後のステップ名に変える
とか注意すればできます。

(行ラベルずれてます)
職名1    職名2    名前    列1    詳細1    詳細2    属性    値    月(全角)    カスタム
バイト職員    A1    山川    報酬    2450        5月    29400    5    5
バイト職員    A1    山川    報酬    2450        6月    66150    6    6
バイト職員    A1    山川    報酬    2450        7月    44100    7    7
バイト職員    A1    山川    報酬    2450        9月    66150    9    9
バイト職員    A1    山川    報酬    2450        10月    58800    10    10


こんな感じになります。

(3)
日(的なもの)を入れる。
同じ月でも、報酬と期末ボーナスの支給があるので、「報酬と期末を区別したい」


で、まず属性で「6月期末」など「期末」の文字が含まれているかの判定を考える。
「Power BIで、ある列に特定の文字列が含まれているか否かの情報を、別の列に記録する方法」のHPを参照しました。
このHPにはCONTAINSSTRING関数が書かれていましたが、うまくいかず、自分は「Text.Contains」にしました。

(手順はあまり覚えていないので、要約すると)
列の追加-カスタム列
数式=Text.Contains([属性],"期末")
とすると、

期末
FALSE
FALSE
FALSE
TRUE
FALSE
FALSE
FALSE
FALSE
TRUE
FALSE
FALSE
FALSE
FALSE

こんな列が作れます。


詳細エディタではこうなっています。

    追加されたカスタム1 = Table.AddColumn(#"名前が変更された列 1", "期末", each Text.Contains([属性],"期末"))


(4)
上記(3)で列を作りましたが、if文でやってみます。

報酬は「1日」、期末は「2日」というように区別したい。

列の追加-カスタム列
数式=if Text.Contains([属性],"期末") then 2 else 1
(注:列名は「日」にしました)
(注:if文は小文字で書きます)

 

詳細エディタではこうなっています。
追加されたカスタム2 = Table.AddColumn(追加されたカスタム1, "日", each if Text.Contains([属性],"期末") then 2 else 1)

以下の感じ

1
1
1
2
1
1
1

(5)
年の列を作ります。年は1~3月は次年なのでif文で作成

詳細エディタではこうなっています。
 追加されたカスタム3 = Table.AddColumn(変更された型2, "年", each if [月]>3 then 2021 else 2020),
    変更された型3 = Table.TransformColumnTypes(追加されたカスタム3,{{"年", type number}}),

上記(4)のように
列の追加-カスタム列
数式=if if [月]>3 then 2021 else 2020
で作成しています。(列名「年」)

次のステップで「列の型」を10進数にしています。

以下の感じ

2021
2021
2021
2021
2021
2021
2021
2021
2021
2021
2020


(6)年月日を作ります
列の追加-カスタム列
数式=#date([年],[月],[日]

でできます。

詳細エディタではこうなっています。
*********************************************************
let
    ソース = Excel.CurrentWorkbook(){[Name="テーブル5"]}[Content],
    変更された型 = Table.TransformColumnTypes(ソース,{{"職名1", type text}, {"職名2", type text}, {"名前", type text}, {"列1", type text}, {"詳細1", type any}, {"詳細2", type any}, {"4月", Int64.Type}, {"5月", Int64.Type}, {"6月", Int64.Type}, {"6月期末", Int64.Type}, {"7月", Int64.Type}, {"8月", Int64.Type}, {"9月", Int64.Type}, {"10月", Int64.Type}, {"11月", Int64.Type}, {"12月期末", Int64.Type}, {"12月", Int64.Type}, {"1月", Int64.Type}, {"2月", Int64.Type}, {"3月", Int64.Type}, {"合計", type any}, {"科目", type text}}),
    フィルターされた行 = Table.SelectRows(変更された型, each ([職名2] = "A1" or [職名2] = "BB1") and ([詳細1] <> "勤務日数" and [詳細1] <> "勤務時間")),
    置き換えられた値 = Table.ReplaceValue(フィルターされた行,null,0,Replacer.ReplaceValue,{"4月"}),
    置き換えられた値1 = Table.ReplaceValue(置き換えられた値,null,0,Replacer.ReplaceValue,{"10月", "11月", "12月期末", "12月", "1月", "2月", "3月"}),
    置き換えられた値2 = Table.ReplaceValue(置き換えられた値1,null,0,Replacer.ReplaceValue,{"4月", "5月", "6月", "6月期末", "7月", "8月", "9月"}),
    削除された列 = Table.RemoveColumns(置き換えられた値2,{"科目", "合計"}),
    選択した列のみをピボット解除しました = Table.Unpivot(削除された列, {"4月", "5月", "6月", "6月期末", "7月", "8月", "9月", "10月", "11月", "12月期末", "12月", "1月", "2月", "3月"}, "属性", "値"),
    区切り記号の前に挿入されたテキスト = Table.AddColumn(選択した列のみをピボット解除しました, "区切り記号の前のテキスト", each Text.BeforeDelimiter([属性], "月"), type text),
    #"名前が変更された列 " = Table.RenameColumns(区切り記号の前に挿入されたテキスト,{{"区切り記号の前のテキスト", "月(全角)"}}),
    追加されたカスタム = Table.AddColumn(#"名前が変更された列 ", "カスタム", each [#"月(全角)"]),

//新しいステップ名を付ける。直前のステップ名を使用する。カンマに注意

    置き換えられた値3 = Table.ReplaceValue(追加されたカスタム,"0","0",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値4 = Table.ReplaceValue(置き換えられた値3,"1","1",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値5 = Table.ReplaceValue(置き換えられた値4,"2","2",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値6 = Table.ReplaceValue(置き換えられた値5,"3","3",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値7 = Table.ReplaceValue(置き換えられた値6,"4","4",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値8 = Table.ReplaceValue(置き換えられた値7,"5","5",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値9 = Table.ReplaceValue(置き換えられた値8,"6","6",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値10 = Table.ReplaceValue(置き換えられた値9,"7","7",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値11 = Table.ReplaceValue(置き換えられた値10,"8","8",Replacer.ReplaceText,{"カスタム"}),
    置き換えられた値12 = Table.ReplaceValue(置き換えられた値11,"9","9",Replacer.ReplaceText,{"カスタム"}),
    変更された型1 = Table.TransformColumnTypes(置き換えられた値12,{{"カスタム", type number}}),
    #"名前が変更された列 1" = Table.RenameColumns(変更された型1,{{"カスタム", "月"}}),
    追加されたカスタム1 = Table.AddColumn(#"名前が変更された列 1", "期末", each Text.Contains([属性],"期末")),
    追加されたカスタム2 = Table.AddColumn(追加されたカスタム1, "日", each if Text.Contains([属性],"期末") then 2 else 1),
    変更された型2 = Table.TransformColumnTypes(追加されたカスタム2,{{"日", type number}}),
    追加されたカスタム3 = Table.AddColumn(変更された型2, "年", each if [月]>3 then 2021 else 2020),
    変更された型3 = Table.TransformColumnTypes(追加されたカスタム3,{{"年", type number}}),
    追加されたカスタム4 = Table.AddColumn(変更された型3, "カスタム", each #date([年],[月],[日])),
    #"名前が変更された列 2" = Table.RenameColumns(追加されたカスタム4,{{"カスタム", "年月日"}})
in
    #"名前が変更された列 2"

*****************************************************

(行ラベルずれてます)
職名1    職名2    名前    列1    詳細1    詳細2    属性    値    月(全角)    月    期末    日    年    年月日
バイト職員    A1    山川    報酬    2450        5月    29400    5    5    FALSE    1    2021    2021/05/01
バイト職員    A1    山川    報酬    2450        6月    66150    6    6    FALSE    1    2021    2021/06/01
バイト職員    A1    山川    報酬    2450        7月    44100    7    7    FALSE    1    2021    2021/07/01
バイト職員    A1    山川    報酬    2450        9月    66150    9    9    FALSE    1    2021    2021/09/01
バイト職員    A1    山川    報酬    2450        10月    58800    10    10    FALSE    1    2021    2021/10/01


早く作れないと意味がないなあ。