重塑表Excel Power Query

问题描述 投票:1回答:1

我在Excel中有一个大表,它是数据收集工具的输出,看起来或多或少像这样:

  DateA    |  ValueA  |   DateB    |  ValueB  | ... |    DateZ   | ValueZ
---------------------------------------------------------------------------
2019-01-01 |    3     | 2019-01-01 |    6     | ... | 2019-01-04 |   7
2019-01-02 |    1     | 2019-01-04 |    2     | ... | 2019-01-05 |   3

我想处理它,所以它想这样:

  Date     |  Value  | Type
-----------------------------
2019-01-01 |   3     |   A
2019-01-02 |   1     |   A
2019-01-01 |   6     |   B
2019-01-04 |   2     |   B
            ...
2019-01-04 |   7     |   Z
2019-01-05 |   3     |   Z

因为这是我们的sql数据库上使用的格式。如何以最乏味的方式执行此操作,最好使用PowerQuery?我想避免蛮力应对和粘贴vba循环。列的数量是固定的,但是稍后可以选择添加另一个列是很好的,然而行数会在某个值(如20,21,20,22,19,20)周围变化。天

excel vba powerquery m
1个回答
1
投票

列很难处理,因此我首先将每列转换为新行作为列表。

ColumnsToRows =
    Table.FromColumns(
        {
         Table.ToColumns(Source),
         Table.ColumnNames(Source)
        },
        {"ColumnValues","ColumnName"}
    )

这应该为您提供如下表格,其中每个列表由相应列中的值组成。例如,顶部列表是{1/1/2019,1/2/2019}。 (列中的部分是添加ColumnName列。)

| ColumnValues | ColumnName |
|--------------|------------|
| [List]       | DateA      |
| [List]       | ValueA     |
| [List]       | DateB      |
| [List]       | ValueB     |
| [List]       | DateZ      |
| [List]       | ValueZ     |

然后我们可以根据每个列表中的数据类型对其进行过滤。要获取日期行,您可以编写:

DataRows =
    Table.SelectRows(
        ColumnsToRows,
        each Value.Type(List.First([ColumnValues])) = type date
    )

这将获得以下过滤表:

| ColumnValues | ColumnName |
|--------------|------------|
| [List]       | DateA      |
| [List]       | DateB      |
| [List]       | DateZ      |

如果你用Table.ExpandListColumn(DataRows, "ColumnValues")扩展第一列,那么你得到

| ColumnValues | ColumnName |
|--------------|------------|
| 1/1/2019     | DateA      |
| 1/2/2019     | DateA      |
| 1/1/2019     | DateB      |
| 1/4/2019     | DateB      |
| 1/4/2019     | DateZ      |
| 1/5/2019     | DateZ      |

逻辑类似于过滤和扩展值行。

ValueRows =
    Table.ExpandListColumn(
        Table.SelectRows(
            ColumnsToRows,
            each Value.Type(List.First([ColumnValues])) = type number
        ),
        "ColumnValues"
    )

这会给你一个类似的表:

| ColumnValues | ColumnName |
|--------------|------------|
| 3            | ValueA     |
| 1            | ValueA     |
| 6            | ValueB     |
| 2            | ValueB     |
| 7            | ValueZ     |
| 3            | ValueZ     |

现在我们只需要将我们想要的列组合到一个表中:

Combine Columns =
    Table.FromColumns(
        {
         DateRows[ColumnValues],
         ValueRows[ColumnValues],
         ValueRows[ColumnName]
        },
        {"Date", "Value", "Type"}
    )

然后在列名中提取Value后面的文本。

ExtractType =
    Table.TransformColumns(
        CombineColumnns,
        {{"Type", each Text.AfterDelimiter(_, "Value"), type text}}
    )

最终表应该与指定的一样:

| Date     | Value | Type |
|----------|-------|------|
| 1/1/2019 | 3     | A    |
| 1/2/2019 | 1     | A    |
| 1/1/2019 | 6     | B    |
| 1/4/2019 | 2     | B    |
| 1/4/2019 | 7     | Z    |
| 1/5/2019 | 3     | Z    |

所有在一个查询中,M代码如下所示:

let
    Source = <Source Goes Here>,
    ColumnsToRows = Table.FromColumns({Table.ToColumns(Source), Table.ColumnNames(Source)}, {"ColumnValues","ColumnName"}),
    DateRows = Table.ExpandListColumn(Table.SelectRows(ColumnsToRows, each Value.Type(List.First([ColumnValues])) = type date), "ColumnValues"),
    ValueRows = Table.ExpandListColumn(Table.SelectRows(ColumnsToRows, each Value.Type(List.First([ColumnValues])) = type number), "ColumnValues"),
    CombineColumnns = Table.FromColumns({DateRows[ColumnValues], ValueRows[ColumnValues], ValueRows[ColumnName]},{"Date", "Value", "Type"}),
    ExtractType = Table.TransformColumns(CombineColumnns, {{"Type", each Text.AfterDelimiter(_, "Value"), type text}})
in
    ExtractType
© www.soinside.com 2019 - 2024. All rights reserved.