使用Power BI提取飞书多维表数据,一次提取超500行的方法

在 Power BI调用飞书API,抓取多维表格中的数据 这一篇中,已经详细说明了500行以内数据的提取方法。

思路

查看 飞书文档 我们可以看到这两个参数可以控制们获取到的数据所在的页数和每页显示的数据行数。
使用Power BI提取飞书多维表数据,一次提取超500行的方法_第1张图片

我们可以使用List.Generate函数去实现循环提取数据直到提取完整。List.Generate的工作原理,可以参考这一篇内容:简单讲解List.Generate 的工作过程。

我们将我们的任务分成3步:

  1. 构建一个提取一页数据的函数。
  2. 引用上一步的函数,构建一个提取所有页数据的函数
  3. 引用上一步的函数,结合获取token的过程,和对数据的处理整理,得到最终想要的数据。

构建一个提取一页数据的函数。

查看我们之前提取不到500行的PQ代码,其中有一步名为“data”。观察它的返加结果。我们看到,除了数据本身items这个字段外,还有has_more和page_token。一个是提示还有没更多的数据,一个是用来定位当前的位置,以使们接下来可以获取之后的数据的。这两个都是要List.Generate中用到的。所以,我们函数的返回结果中,也应该包含这2项。
使用Power BI提取飞书多维表数据,一次提取超500行的方法_第2张图片

复制 之前写的提取少于500行数据的PQ代码中的如下部分,进行改写。改写为一个传入token和page_token参数,返回一个包括items、has_more、new_page_token的记录(record)的函数。
使用Power BI提取飞书多维表数据,一次提取超500行的方法_第3张图片

改写好后的函数如下:

(token as text,page_token as any )=>
let    
    app_token = "*********",
    table_id = "**********",
    url = "https://open.feishu.cn/open-apis/bitable/v1/apps/" & app_token & "/tables/" & table_id & "/records",

    // 发送GET请求获取数据
    response = if page_token = null then
        Json.Document(
            Web.Contents(
                url & "?page_size=500",
                [
                    Headers = [
                        Authorization = "Bearer " & token
                    ]
                ]
            )
        )
    else 
        Json.Document(
            Web.Contents(
                url & "?page_size=500&page_token=" & page_token,
                [
                    Headers = [
                        Authorization = "Bearer " & token
                    ]
                ]
            )
        ),
    data = response[data],
    items = data[items],
    has_more=data[has_more],
    new_page_token=data[page_token],
    rst=[items=items,has_more=has_more,new_page_token=new_page_token]
in
    rst

在原先的 Json.Document(Web.Contents()) 部分,加了一个if作判断,如果page_token是空,就在URL的后面加上"?page_size=500",这是针对提取第一页的内容,此时不用传page_token参数。如果是page_token不是空,就在URL的后面加上"?page_size=500&page_token=" & page_token,这是针对提取第一页以后的内容,此时要传递page_token参数。

构建一个提取所有页数据的函数

这个函数将调用上面构建好的函数fnGetDataFromFeishu
这个函数需要传一个token参数,返回一个数据的列表(list)。
函数的代码如下:

(token as any)=>
let
    源 = List.Generate(
        ()=>[now_response=null,pre_token=null,has_more=true,a=0],
        each [a] = 0,
        each [
            now_response=fnGetDataFromFeishu(token,[pre_token]),
            pre_token=now_response[new_page_token],
            has_more=now_response[has_more],
            a= if [has_more] then [a] else [a]+1
        ],
        each if [now_response]<>null then [now_response][items] else {} 
    )
in
    源

本来我是想写成如下这样:

(token as any)=>
let
    源 = List.Generate(
        ()=>[now_response=null,pre_token=null,has_more=true],
        each [has_more],
        each [
            now_response=fnGetDataFromFeishu(token,[pre_token]),
            pre_token=now_response[new_page_token],
            has_more=now_response[has_more]
        ],
        each if [now_response]<>null then [now_response][items] else {} 
    )
in
    源

也就是不增加字段a,使用has_more来判断循环是否继续。但因为实际上List.Generate是先计算参数3,再根据参数2去判断是否将参数4加入到结果列表。于是,当我们获得最后一页的数据时,参数3中has_more变成了false,参数2进行判断时,会判定不将这一次循环的结果加入结果列表中。这样就会缺少最后一页数据。所以,增加了字段a,让它去读取上一次循环中的has_more,这样就可以多循环一次。注意a= if [has_more] then [a] else [a]+1这段代码中的has_more是带方括号的,所以引用的是上一次循环的结果中的参数3中的字段,而不是本次的。这一点可以参考这篇内容:List.Generate使用时需要特别注意方括号的使用。

结合获取token的过程,和对数据的处理整理,得到最终想要的数据

这一步就没啥要补充的了,就是引用一下上步构建的函数fnGenerateDate,再将它返回的结果用List.Combine处理一下。其它代码就是照抄之前提取少于500行数据时使用的代码。
代码如下:

let
    // 定义请求头
    headers = [
        #"Content-Type"="application/json; charset=utf-8"
    ],

    // 定义请求参数
    params = [
        app_id = "***************",
        app_secret = "***************"
    ],

    // 发送POST请求获取访问令牌
    tokenResponse = Json.Document(
        Web.Contents(
            "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
            [
                Headers = headers,
                Content = Json.FromValue(params)
            ]
        )
    ),
    token = tokenResponse[tenant_access_token],

    items=List.Combine(fnGenerateDate(token)),

    转换为表 = Table.FromRecords(items),
    删除的其他列 = Table.SelectColumns(转换为表,{"fields"}),
    #"展开的“fields”" = Table.ExpandRecordColumn(删除的其他列, "fields", {"上报时间", "回访日期", "姓名", "客户反馈", "客户所在公司", "岗位", "所属大区", "是否续费", "是否达成销售目标", "月份", "续费金额", "职务", "负责人", "负责跟进人", "销售额"}, {"上报时间", "回访日期", "姓名", "客户反馈", "客户所在公司", "岗位", "所属大区", "是否续费", "是否达成销售目标", "月份", "续费金额", "职务", "负责人", "负责跟进人", "销售额"}),
    #"展开的“是否达成销售目标”" = Table.ExpandListColumn(#"展开的“fields”", "是否达成销售目标"),
    #"展开的“是否达成销售目标”1" = Table.ExpandRecordColumn(#"展开的“是否达成销售目标”", "是否达成销售目标", {"text"}, {"text"}),
    #"展开的“负责人”" = Table.ExpandListColumn(#"展开的“是否达成销售目标”1", "负责人"),
    #"展开的“负责人”1" = Table.ExpandRecordColumn(#"展开的“负责人”", "负责人", {"name"}, {"name"}),
    #"展开的“负责跟进人”" = Table.ExpandListColumn(#"展开的“负责人”1", "负责跟进人"),
    #"展开的“负责跟进人”1" = Table.ExpandRecordColumn(#"展开的“负责跟进人”", "负责跟进人", {"name"}, {"name.1"}),
    重命名的列 = Table.RenameColumns(#"展开的“负责跟进人”1",{{"name", "负责人"}, {"name.1", "跟进人"}}),
    更改的类型 = Table.TransformColumnTypes(重命名的列,{{"上报时间", type text}}),
    大写的文本 = Table.TransformColumns(更改的类型, {{"回访日期", each if _ =null then null else #datetime(1970, 1, 1, 0, 0, 0) + #duration(0, 0, 0, Number.From(_) / 1000)},{"上报时间", each #datetime(1970, 1, 1, 0, 0, 0) + #duration(0, 0, 0, Number.From(_) / 1000)}})
in
    大写的文本

示例文件下载

链接:百度网盘

你可能感兴趣的:(飞书,数据分析,powerbi)