【问题标题】:Power Query - regional settingsPower Query - 区域设置
【发布时间】:2019-12-12 14:28:17
【问题描述】:

我为我的部门制作了一个最佳实践表,它在我自己的计算机上完美运行(en-US 区域设置),但是当我将它发送给同事时,一切都崩溃了(da-DK 区域设置)。

该部门一半使用 en-US,另一半使用 da-DK。不是每个人都可以使用相同的选项,所以我想创建一个可以自动处理两者的工作表。

在 en-US 中创建的 csv 文件使用 "," 分隔符和 "."对于十进制,而 da-DK 设置使用“;”作为分隔符和“,”用于小数。

我最好如何解决这个问题?

我有以下两个相同的数据查询

Data1.csv:

    Panel/Node/Case,    MXX (kNm/m),    MYY (kNm/m)
    1/ 1/ 1,            145.46,         145.46  
    1/ 1/ 2,            98.83,          98.83   
    1/ 1/ 3 (C),        244.30,         244.30  
    1/ 2/ 1,            19.80,          19.80   
    1/ 2/ 2,            13.46,          13.46   
    1/ 2/ 3 (C),        33.26,          33.26   
    1/ 3/ 1,            19.80,          19.80   
    1/ 3/ 2,            13.46,          13.46   
    1/ 3/ 3 (C),        33.26,          33.26   
    1/ 4/ 1,            145.46,         145.46  
    1/ 4/ 2,            98.83,          98.83   
    1/ 4/ 3 (C),        244.30,         244.30

Data2.csv:

    Panel/Node/Case;    MXX (kNm/m);    MYY (kNm/m)
    1/ 1/ 1;            145,46;         145,46
    1/ 1/ 2;            98,83;          98,83
    1/ 1/ 3 (C);        244,30;         244,30
    1/ 2/ 1;            19,80;          19,80
    1/ 2/ 2;            13,46;          13,46
    1/ 2/ 3 (C);        33,26;          33,26
    1/ 3/ 1;            19,80;          19,80
    1/ 3/ 2;            13,46;          13,46
    1/ 3/ 3 (C);        33,26;          33,26
    1/ 4/ 1;            145,46;         145,46
    1/ 4/ 2;            98,83;          98,83
    1/ 4/ 3 (C);        244,30;         244,30

我正在考虑使用替换值函数来替换我需要的字符,但由于两个查询都包含一个“,”,这证明很困难。

【问题讨论】:

    标签: delimiter powerquery regional-settings


    【解决方案1】:

    也许有一些动态/内置的方法可以检测文件内容的语言环境和分隔符。我还没有找到一个。在有人出现并指出更好的方法之前,也许下面可以作为临时解决方案。

    • 以下代码中的 parseCsv 函数尝试推断分隔符(它假定分隔符始终出现在 CSV 的第一行中,紧跟在 Panel/Node/Case 之后)。
    • 它还尝试将最后两列的值从文本转换为数字(通过将, 替换为.)。如果你不想要这种行为,你可以从代码中删除它。此外,此转换仅适用于使用 . 作为小数点分隔符的语言环境。 (如果您需要支持其他文化/语言环境,尝试推断文化/语言环境并将其作为第二个参数传递给 Number.FromText 可能更有意义。)

    let
        data1 = Text.ToBinary(
        "Panel/Node/Case,    MXX (kNm/m),    MYY (kNm/m)
        1/ 1/ 1,            145.46,         145.46  
        1/ 1/ 2,            98.83,          98.83   
        1/ 1/ 3 (C),        244.30,         244.30  
        1/ 2/ 1,            19.80,          19.80   
        1/ 2/ 2,            13.46,          13.46   
        1/ 2/ 3 (C),        33.26,          33.26   
        1/ 3/ 1,            19.80,          19.80   
        1/ 3/ 2,            13.46,          13.46   
        1/ 3/ 3 (C),        33.26,          33.26   
        1/ 4/ 1,            145.46,         145.46  
        1/ 4/ 2,            98.83,          98.83   
        1/ 4/ 3 (C),        244.30,         244.30", TextEncoding.Utf8),
    
        data2 = Text.ToBinary(
        "Panel/Node/Case;    MXX (kNm/m);    MYY (kNm/m)
        1/ 1/ 1;            145,46;         145,46
        1/ 1/ 2;            98,83;          98,83
        1/ 1/ 3 (C);        244,30;         244,30
        1/ 2/ 1;            19,80;          19,80
        1/ 2/ 2;            13,46;          13,46
        1/ 2/ 3 (C);        33,26;          33,26
        1/ 3/ 1;            19,80;          19,80
        1/ 3/ 2;            13,46;          13,46
        1/ 3/ 3 (C);        33,26;          33,26
        1/ 4/ 1;            145,46;         145,46
        1/ 4/ 2;            98,83;          98,83
        1/ 4/ 3 (C);        244,30;         244,30", TextEncoding.Utf8),
    
        parseCsv = (someFile as binary) =>
            let
                lines = Lines.FromBinary(someFile, QuoteStyle.Csv, false, TextEncoding.Utf8),
                firstLine = List.First(lines),
                expectedDelimiterPosition = Text.Length("Panel/Node/Case"), 
                delimiterInferred = Text.At(firstLine, expectedDelimiterPosition),
                csv = Csv.Document(someFile, [Delimiter = delimiterInferred, Encoding = TextEncoding.Utf8, QuoteStyle = QuoteStyle.Csv]),
                promoted = Table.PromoteHeaders(csv, [PromoteAllScalars=true]),
                lastTwoColumnsAsNumbers = 
                    let
                        lastTwoHeaders = List.LastN(Table.ColumnNames(promoted), 2),
                        replaceAndConvertToNumber = (someText as text) as number => Number.From(Text.Replace(someText, ",", ".")),
                        transformers = List.Transform(lastTwoHeaders, each {_, replaceAndConvertToNumber, type number}),
                        transformed = Table.TransformColumns(promoted, transformers)
                    in transformed
            in lastTwoColumnsAsNumbers,
        parsed1 = parseCsv(data1),
        parsed2 = parseCsv(data2),
        parsed3 = parseCsv(File.Contents("C:\Users\MRCH\Desktop\Data1.csv"))
    in
        parsed3
    

    • 要实现这一点,您可以复制上面的代码,创建一个空白查询(在我的 Excel 版本中,我通过以下方式执行此操作:数据 > 获取数据 > 从其他来源 > 从空白查询),单击高级编辑器(靠近左上角),删除所有现有代码,粘贴您复制的内容,然后点击“完成”。
    • 要使parseCsv 函数与文件路径一起工作,例如,您可以将parsed1 = parseCsv(data1) 更改为parsed1 = parseCsv(File.Contents("SOME_FILE_PATH")),其中SOME_FILE_PATH 是您机器上Data1.csv 的文件路径(保留双引号)。
    • 在查询编辑器中,您可以单击并查看表达式/步骤parsed1parsed2(这基本上是parseCsv 函数分别为Data1.csvData2.csv 返回的内容)。 data1data2 仅用于演示目的,您可以将它们替换为 CSV 的实际二进制内容。

    如果这没有帮助,请告诉我在哪里可以改进我的解释。

    【讨论】:

    • 非常感谢您的回复!这有点超出我的能力,所以我不确定如何从那里开始,所以一个工作示例会很有帮助!
    • @Martin,如果你想再看一遍,我已经重写了部分答案。
    • 谢谢,但我不明白的主要是如何导入数据?通常我会使用 "Source = Csv.Document(File.Contents("C:\Users\MRCH\Desktop\Data1.csv"),[Delimiter=",", Columns=3, Encoding=1200, QuoteStyle=QuoteStyle .None])”但这如何转化为您所写的内容?我想导入 CSV 文件,而您已在查询中“定义”它?
    • 尝试parseCsv(File.Contents("C:\Users\MRCH\Desktop\Data1.csv")),假设您的代码中包含函数parseCsv。添加了parsed3 表达式/步骤作为示例,因此您可以查看它是否适用于您的文件。
    • 太棒了,一切似乎都在工作。非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多