여러 열의 구분 기호로 행을 나누면서 테이블로 만드는 방법 | Power Query

구분 기호로 셀 분할은 열 분할 메뉴라면 쉽게 할 수 있습니다.
하지만 그러한 셀이 여러 열에 걸친 경우 열 분할 작업에서는 잘 테이블이 되지 않습니다. 그래서 나름대로의 해답을 남겨 둡니다.

※이 문제는 Ken Puls씨가 출제된 것 입니다.
Ken Puls는 "M Is for (Data) Monkey"의 저자 중 하나입니다.

설문



이런 상태로 왼쪽에서 오른쪽으로 변환하고 싶다. 이하, 단락 문자는 개행 문자만인 경우로 해설합니다.

※아래의 코드를 상세 에디터에 붙이면, 파란 쪽의 테이블과 같은 것이 생깁니다. 이 쿼리를 질문이라고 합니다.

설문
let
    Source = "i65W8swry89MTvV0UbIyNDI20VHyLEnNBfGUDA0MDWNKDQwMEg0NjKAsIwMjIyUdpcDSxLySzJJKkCqoBIQyBkoGFAHNA8pY6lmawvTDmeZAllKtDrq9pljtxbQNao0hVmtwmG2GYrYB3E8G2H1igmS2oQnccFPshpsjDAeZjWygIdwcsDGYei1Q9Bph12sG0hoLAA==",
    Custom1 = Binary.Decompress(Binary.FromText(Source),Compression.Deflate),
    #"Imported JSON" = Table.FromRecords(Json.Document(Custom1,932))
in
    #"Imported JSON"

해답 1~하드 코딩



질문의 테이블과 같은 열 수, 열 이름, 순서가 아니면, 움직이지 않습니다.
그렇지만, 우선은 여기로부터 시작된다고 하는 것으로 좋다고 생각합니다.

코드



해답 예 1
let
    Source = 設問,
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"InvoiceID", Int64.Type}, {"ItemID", type text}, {"Quantity", type text}, {"Price", type text}}),
    ColumnNames =Table.ColumnNames(Source),
    SplitByDelimiter = Table.TransformColumns(#"Changed Type",{
                    {"ItemID",each Splitter.SplitTextByDelimiter("#(lf)")(_)},
                    {"Quantity",each Splitter.SplitTextByDelimiter("#(lf)")(_)},
                    {"Price",each Splitter.SplitTextByDelimiter("#(lf)")(_)}
                    }
              ),
    EachRowToTable =Table.TransformRows(SplitByDelimiter,each
                        Table.FromColumns({{[InvoiceID]},[ItemID],[Quantity],[Price]},ColumnNames)                            
                    ),
    CombineTables = Table.Combine(EachRowToTable),
    #"Filled Down" = Table.FillDown(CombineTables,{"InvoiceID"})
in
    #"Filled Down"

처리 도중 경과



SplitByDelimiter의 위치

구분 기호가 있는 곳도 없는 곳도 각각, 결과가 리스트가 되어 있습니다.


EachRowToTable의 위치



함수 정보



· Splitter.SplitTextByDelimiter 함수
Splitter 함수군의 하나로, 1종의 단락 문자를 복수회 사용하는 경우에 사용합니다.
그 밖에도 여러 구분 기호를 여러 번 사용하는 경우 Splitter.SplitTextByAnyDelimiter가
한 번만 사용하는 경우 Splitter.SplitTextByEachDelimiter가 있습니다.
· Table.TransformRows 함수
조작감은 Table.AddColumn에 가깝네요.
· Table.FromColumns 함수
각 열의 내용을 리스트로 나타내고, 그것을 리스트에 정리한 것이 인수가 됩니다.

해답 2~데이터 부분의 열명·열수의 변동에 대응



전제


  • 1열째는 단락 문자에 의한 분할이 불필요한 것.
  • 2열째 이후에 단락 문자에 의한 분할 대상일 것.
  • 2열째 이후에 들어가 있는 단락 문자의 개수는, 행으로 보았을 경우에 각 열로 동일할 것.

  • 코드



    함수로 해 보았습니다.

    fx_ 다중 열 분할
    (TBL as table,TitleColumn as text,delimiter as text)=>
    let
        ColumnNames = Table.ColumnNames(TBL),
        NumOfColumns =Table.ColumnCount(TBL),
        //データ列をまとめて処理するための関数を用意する。各列名と相手方をペアにしたリストができる。
        fx_paring =(OtherParty)=>List.Zip({List.Skip(ColumnNames,1),
                                           List.Repeat({OtherParty},NumOfColumns-1)}
                                 ),
    
        //テキスト型を保証しないと、Split関数が機能しないため。
        #"Changed Type" = Table.TransformColumnTypes( TBL,fx_paring(type text) ),
    
        Custom1 = Table.TransformColumns(#"Changed Type",
                        //Split関数をペアにしたリスト
                        fx_paring((x)=>Splitter.SplitTextByDelimiter(delimiter)(x))
                  ),
        Custom2 = Table.Combine(
                        //テーブルの各行ごとに処理をし、その結果のリストが出来上がる。
                        Table.TransformRows(Custom1,each
                            //1行目は中身がリストでないので、リストに入れてやる。
                            Table.FromColumns({{Record.ToList(_){0}}} & List.Skip(Record.ToList(_),1),
                                              ColumnNames
                            )
                        )
                  ),
        #"Filled Down" = Table.FillDown(Custom2,{TitleColumn})
    in
        #"Filled Down"
    
    

    실행 예



    이런 식으로 상세 편집기의 수식 바에 넣어 주면 실행할 수 있습니다.
    = fx_複数列分割(設問, "InvoiceID", "#(lf)")
    

    실행 예 2



    개행이 아니라, 열이 늘어난 예를 설문 2로 해, 그래서 실행해 보겠습니다.

    질문 2
    let
        Source = "jY+xCsIwEIbf5eZicmnSWjerSzZdXIxDkQ6FmoIkgojv7iWDto2Cyx33H3wf//EB2t6G7tzqLaxQ5DID7dpLuAA5omHIBU3BhYAM9r6xrnP38KXQsJzCQ9P7xnWDpXRtWG3YhtLdlaiUVItKBUpcJU14ZnOrSqypj2Q4k5GpTkw/FMVEwWMxnlaSaZ9xGZTRob47yo8jKMZsnGCt7/s3NDJT2HICE3/CisA6vQA=",
        Custom1 = Binary.Decompress(Binary.FromText(Source),Compression.Deflate),
        #"Imported JSON" = Table.FromRecords(Json.Document(Custom1,932))
    in
        #"Imported JSON"
    

    실행 그 2
    = fx_複数列分割(設問2, "InvoiceID", "/")
    

    이와 같이 무사히 변환되고 있습니다.


    보충: fx_paring



    그냥 사용자 정의 함수입니다.
    예를 들어, type text를 인수로 해서 실행하면, 이렇게 됩니다. (알기 쉽도록 테이블로 변환했습니다)

    좋은 웹페이지 즐겨찾기