Power Query 系列 (20) - 如何在外部使用Power Query提供的服务

Power Query 作为桌面端数据清理和转换的工具,能极大解放生产力,将繁琐的数据处理工作从重复的劳动中解放出来。那么,Power Query 能否对外提供计算服务呢?或者说 Power Query 有没有对外提供的编程接口? 根据我的探索,似乎没有,但在网络上找到下面的两种 walkaround 方式,都比较小众。所以如果真的需要数据处理、数据分析服务的话,不如选择其他的方案,比如 pandas 等等,拥有更大的自由度。

  • 方式:将数据加载到 Power Pivot,通过 ADO 方式调用 Power Pivot 的编程接口
  • 方式:利用微软的 Power Query SDK,在 .NET 平台使用 M 语言,获取查询结果。

本篇主要介绍第一种方式,第二种方式给出一些参考链接。

利用 Power Pivot 的数据模型编程接口

貌似 PQ 没有对外的编程接口,但是 Power Pivot 有通过 Excel 工作簿的编程接口,所以我们可以将数据加载到 Power Pivot, 然后在外部调用。因为本文主要是讲 Power Query ,所以对 Power Pivot 不做展开。Power Pivot 是微软推出的 Excel COM 加载项 (COM Add-in),可以在微软官方免费下载并安装,然后启用加载项即可。安装之后,启用方法如下:通过【文件】>【选项】打开如下界面,选择加载项类型的【COM加载项】,点击转到按钮。

image

然后在出现的对话框中,勾上"Microsoft Power Pivot for Excel"。如果想不启用该插件,也是通过相同的路径进入该界面,去掉这个勾。

image

接下来,以之前文章讲解的 PQ 实现的进出存查询为例,进一步讲解如何通过 VBA + ADO 调用 PQ 的查询结果。打开上一篇示例数据的 Excel 文件,选择 stock_balance 查询,点击右键菜单的【加载到】菜单:

image

选择“将此数据添加到数据模型”:

image

然后在【数据】选项卡,点击【管理数据模型】功能项:

image

这样就进入了 Power Pivot 的界面。暂时不对 Power Pivot 的细节展开。

image

打开一个新的 Excel 工作簿,按下 Alt + F11 进入 VBE (Visual Basic Editor) 环境。在 VBE 环境中,通过【工具】>【引用】添加 Microsoft ActiveX Data Model 的引用。这个是 COM 库,运行 ADO 需要。

image

新建一个模块 (Module),在模块中新建一个函数 ExportExcelDataModel。该函数实现将 Excel Data Model 导出到工作表:

Public Function ExportExcelDataModel(
    excelFilePath As String, 
    modelName As String, 
    targetSheet As Worksheet)
    
    '''Reference: Microsoft ActiveX Data Objects
 
    Dim wbTarget As Workbook  'target workbook
    Dim ws As Worksheet
    Dim conn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim sQueryString As String

    'Suppress alerts and screen updates
    Application.ScreenUpdating = False
    Application.DisplayAlerts = False

    Err.Clear
    On Error GoTo ErrHandler
    
    Set wbTarget = Application.Workbooks.Open(excelFilePath)
 
    'Make sure the model is loaded
    wbTarget.Model.Initialize
    wbTarget.Model.Refresh

    Set conn = wbTarget.Model.DataModelConnection.ModelConnection.ADOConnection
    sQueryString = "EVALUATE '" & modelName & "'"
    
    Set rs = New ADODB.Recordset
    rs.CursorLocation = adUseClient
    rs.Open sQueryString, conn
    
    targetSheet.Cells.ClearContents
    ' Write header
    Dim colIndex As Integer
    For colIndex = 0 To rs.Fields.Count - 1
        targetSheet.Range("A1").Offset(0, colIndex).Value = rs.Fields(colIndex).Name
    Next
    
    ' Write Lines
    targetSheet.Range("A1").Offset(1, 0).CopyFromRecordset rs
 
    rs.Close
    Set rs = Nothing    
    ' Close workbook
    wbTarget.Close
 
ExitPoint:
    Application.ScreenUpdating = True
    Application.DisplayAlerts = True

    Set rs = Nothing
    Exit Function
 
ErrHandler:
    MsgBox "An error occured - " & Err.Number & "," & Err.Description, vbOKOnly
    Resume ExitPoint
End Function

因为本文的主题是 PQ,所以不对代码的细节进行讲解,只稍微提一下 ADO 读取 Excel Data Model 的要点:

  • 通过 someWorkbook.Model.DataModelConnection.ModelConnection.ADOConnection 获得数据连接
  • CopyFromRecordSet 方法要求 RecordSet 的 Cursor Location 为 adUseClient,否则结果错误,并没有抛出 Exception 或 Error,而是数据出现错误。如果手工代码循环的方式获取,则没有问题。

然后再添加一个子例程,调用函数 ExportExcelDataModel,下面的调用过程既是调用代码,也能体现函数的调用方法。

Public Sub DoExport()
    Dim filePath As String
    filePath = ThisWorkbook.Path & "\pqservice.xlsx"

    Dim conn As New ADODB.Connection
    conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
        "Extended Properties=""Excel 12.0;HDR=No"";" & _
        "data source=" & filePath
    
    ' Update cell in another excel workbook
    Dim sql As String
    sql = "UPDATE [Criteria$A1:B3] SET F2=5 WHERE F1='month'"
    conn.Open
    conn.Execute sql
    conn.Close
    
    ' Retrieve data
    Dim sht As Worksheet
    Set sht = Sheet1    
    Call ExportExcelDataModel(filePath, "stock_balance", sht)
    
    sht.Activate
End Sub

因为需要将筛选条件:月份,从当前工作簿传递到目标工作簿,我采用了 ADO 直接读写 Excel 工作表的方法。但我平时很少用到 ADO 读写 Excel 工作表的方式,因为数据尽可能存放在数据库中,而不是 Excel。在目标工作簿 -- 即提供 Power Query 服务的 Excel 工作表中,筛选条件界面如下:

image

所以用

sql = "UPDATE [Criteria$A1:B3] SET F2=5 WHERE F1='month'"

表示更新的 SQL 语句。连接字符串中 HDR = No,表示不启用 Header Row,所以此语句 F1 表示 A 列,F2 表示 B 列。Criteria 是工作表名称 (worksheet name)。

本示例代码提供的功能:

  • 将目标工作表的 B3 单元格值修改为 5 (月份条件)
  • 然后对数据据模型进行刷新操作,确保获取的是最新计算的结果
  • 将 Data Model 的计算结果写入 RecordSet 对象,再将 RecordSet 对象数据写入当前工作簿的 Sheet1 (函数的功能)

从理论上来说,这种方法适用于所有能操作 COM 对象 (ADO ActiveX) 的编程语言。

Power Query SDK

微软提供了 Power Query SDK,从而赋予了在 .net 平台中可以直接使用 M 语言的功能。尽管官方的说法,Power Query SDK 已经在 Visual Studio 2019 中可以使用,但我在安装的时候没有成功,也不打算在 Visual Studio 2017 或更老的版本中折腾,这里只能给出相关的连接,有兴趣的读者请自行探索。

Power Query SDK 是一扩展名为 vsix 的文件,在 Visual Studio 中安装的方法请参考:vs2015如何安装vsix扩展工具

网上为数不多的参考文章:

示例数据和代码

github - Consuming Power Query Service

参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容