当我必须使用 Python 从 PowerPivot 模型中读取一些数据时,看似微不足道的任务变成了真正的噩梦。我相信在过去的几天里我已经对此进行了很好的研究,但现在我遇到了困难,并且希望得到 Python/SSAS/ADO 社区的一些帮助。
基本上,我想要做的就是以编程方式访问存储在 PowerPivot 模型中的原始数据 - 我的想法是通过下面列出的方法之一连接到底层 PowerPivot(即 MS Analysis Services)引擎,列出模型中包含的表,然后使用简单的 DAX 查询从每个表中提取原始数据(类似于EVALUATE (table_name)
)。简单易行,对吧?嗯,也许不是。
0.一些背景信息
正如您所看到的,我尝试了几种不同的方法。我将尝试尽可能仔细地记录所有内容,以便那些不熟悉 PowerPivot 功能的人能够很好地了解我想要做什么。
首先,关于以编程方式访问 Analysis Services 引擎的一些背景知识(它说是 2005 SQL Server,但所有这些都应该仍然适用):SQL Server 数据挖掘可编程性 https://msdn.microsoft.com/en-us/library/ms345148.aspx and 用于 Analysis Services 连接的数据提供程序 https://msdn.microsoft.com/en-us/library/dn141152.aspx.
我将在下面的示例中使用的示例 Excel/PowerPivot 文件可以在此处找到:Microsoft PowerPivot for Excel 2010 和 PowerPivot in Excel 2013 示例 https://www.microsoft.com/en-us/download/details.aspx?id=102.
另请注意,我使用的是 Excel 2010,因此我的一些代码是特定于版本的。例如。wb.Connections["PowerPivot Data"].OLEDBConnection.ADOConnection
应该wb.Model.DataModelConnection.ModelConnection.ADOConnection
如果您使用的是 Excel 2013。
我将在整个问题中使用的连接字符串基于此处找到的信息:使用 C# 连接到 PowerPivot 引擎 https://social.technet.microsoft.com/Forums/sqlserver/en-US/0b9499f6-f80f-4dcc-8ab9-c52574b14a70/connect-to-powerpivot-engine-with-c。此外,某些方法显然需要在数据检索之前对 PowerPivot 模型进行某种初始化。看这里:从 VBA 自动执行 PowerPivot 刷新操作 https://gobansaor.wordpress.com/2011/08/31/automating-powerpivot-refresh-operation-from-vba/.
最后,这里有几个链接表明这应该是可以实现的(但请注意,这些链接主要指的是 C#,而不是 Python):
- 已连接到 PowerPivot DataModel,如何用它填充数据集? https://stackoverflow.com/questions/24763513/made-connection-to-powerpivot-datamodel-how-can-i-fill-a-dataset-with-it
- 使用 C# 连接到 PowerPivot https://stackoverflow.com/questions/8242557/connecting-to-powerpivot-with-c-sharp
- 2013 C# 与 Power Pivot 数据模型的连接 https://stackoverflow.com/questions/24643366/2013-c-sharp-connection-to-powerpivot-datamodel
-
连接 Tableau 和 PowerPivot。它就是有效的。 http://tableaulove.tumblr.com/post/76758976141/connecting-tableau-and-powerpivot-it-just-works(表明外部应用程序实际上可以读取 PowerPivot 模型数据 - 请注意,Tableau 加载项安装
Interop.ADODB.dll
程序集,我猜它是用来访问 PowerPivot 数据的)
1.使用ADOMD
import clr
clr.AddReference("Microsoft.AnalysisServices.AdomdClient")
import Microsoft.AnalysisServices.AdomdClient as ADOMD
ConnString = "Provider=MSOLAP;Data Source=$Embedded$;Locale Identifier=1033;
Location=H:\\PowerPivotTutorialSample.xlsx;SQLQueryMode=DataKeys"
Connection = ADOMD.AdomdConnection(ConnString)
Connection.Open()
在这里,问题似乎是 PowerPivot 模型尚未初始化:
AdomdConnectionException: A connection cannot be made. Ensure that the server is running.
2.使用AMO
import clr
clr.AddReference("Microsoft.AnalysisServices")
import Microsoft.AnalysisServices as AMO
ConnString = "Provider=MSOLAP;Data Source=$Embedded$;Locale Identifier=1033;
Location=H:\\PowerPivotTutorialSample.xlsx;SQLQueryMode=DataKeys"
Connection = AMO.Server()
Connection.Connect(ConnString)
同样的故事,“服务器没有运行”:
ConnectionException: A connection cannot be made. Ensure that the server is running.
请注意,从技术上讲,AMO 并不用于查询数据,但我将其作为连接 PowerPivot 模型的潜在方式之一。
3.使用ADO.NET
import clr
clr.AddReference("System.Data")
import System.Data.OleDb as ADONET
ConnString = "Provider=MSOLAP;Data Source=$Embedded$;Locale Identifier=1033;
Location=H:\\PowerPivotTutorialSample.xlsx;SQLQueryMode=DataKeys"
Connection = ADONET.OleDbConnection()
Connection.ConnectionString = ConnString
Connection.Open()
这类似于使用 python 或 IronPython 访问 mssql 最简单的方法是什么? https://stackoverflow.com/a/301746。不幸的是,这也行不通:
OleDbException: OLE DB error: OLE DB or ODBC error: The following system error occurred:
The requested name is valid, but no data of the requested type was found.
4.通过adodbapi模块使用ADO
import adodbapi
ConnString = "Provider=MSOLAP;Data Source=$Embedded$;Locale Identifier=1033;
Location=H:\\PowerPivotTutorialSample.xlsx;SQLQueryMode=DataKeys"
Connection = adodbapi.connect(ConnString)
如同Python 和 MS Access VBA 之间 OLEDB/ODBC 的相反工作方式 https://stackoverflow.com/questions/25951912/oppposite-workings-of-oledb-odbc-between-python-and-ms-access-vba。我得到的错误是:
OperationalError: (com_error(-2147352567, 'Exception occurred.', (0, u'Microsoft OLE DB
Provider for SQL Server 2012 Analysis Services.', u'OLE DB error: OLE DB or ODBC error: The
following system error occurred: The requested name is valid, but no data of the requested
type was found...
这与上面的 ADO.NET 的问题基本相同。
5.通过Excel/win32com模块使用ADO
from win32com.client import Dispatch
Xlfile = "H:\\PowerPivotTutorialSample.xlsx"
XlApp = Dispatch("Excel.Application")
Workbook = XlApp.Workbooks.Open(Xlfile)
Workbook.Connections["PowerPivot Data"].Refresh()
Connection = Workbook.Connections["PowerPivot Data"].OLEDBConnection.ADOConnection
Recordset = Dispatch('ADODB.Recordset')
Query = "EVALUATE(dbo_DimDate)" #sample DAX query
Recordset.Open(Query, Connection)
这种方法的想法来自这篇使用 VBA 的博客文章:使用 VBA 将表或 DAX 查询从 Power Pivot 导出到 CSV https://www.powerpivotblog.nl/export-a-table-or-dax-query-from-power-pivot-to-csv-using-vba/。请注意,此方法使用显式刷新命令来初始化模型(即“服务器”)。这是错误消息:
com_error: (-2147352567, 'Exception occurred.', (0, u'ADODB.Recordset', u'Arguments are of
the wrong type, are out of acceptable range, or are in conflict with one another.',
u'C:\\Windows\\HELP\\ADO270.CHM', 1240641, -2146825287), None)
然而,ADO 连接似乎已建立:
-
type(Connection)
回报instance
-
print(Connection)
回报Provider=MSOLAP.5;Persist Security Info=True;Initial Catalog=Microsoft_SQLServer_AnalysisServices;Data Source=$Embedded$;MDX Compatibility=1;Safety Options=2;ConnectTo=11.0;MDX Missing Member Mode=Error;Subqueries=2;Optimize Response=3;Cell Error Mode=TextValue
问题似乎出在 ADODB.Recordset 对象的创建上。
6.通过Excel/win32com使用ADO,直接使用ADODB.Connection
from win32com.client import Dispatch
ConnString = "Provider=MSOLAP;Data Source=$Embedded$;Locale Identifier=1033;
Location=H:\\PowerPivotTutorialSample.xlsx;SQLQueryMode=DataKeys"
Connection = Dispatch('ADODB.Connection')
Connection.Open(ConnString)
如同从 Python 连接到 Access [重复] https://stackoverflow.com/a/12761442 and Win32平台下使用ADO查询访问(Python秘籍) https://code.activestate.com/recipes/196462-query-access-using-ado-in-win32-platform/。不幸的是,Python 吐出的错误与上面两个示例中的错误相同:
com_error: (-2147352567, 'Exception occurred.', (0, u'Microsoft OLE DB Provider for SQL
Server 2012 Analysis Services.', u'OLE DB error: OLE DB or ODBC error: The following system
error occurred: The requested name is valid, but no data of the requested type was found.
..', None, 0, -2147467259), None)
7.通过Excel/win32com使用ADO,直接使用ADODB.Connection加模型刷新
from win32com.client import Dispatch
Xlfile = "H:\\PowerPivotTutorialSample.xlsx"
XlApp = Dispatch("Excel.Application")
Workbook = XlApp.Workbooks.Open(Xlfile)
Workbook.Connections["PowerPivot Data"].Refresh()
ConnStringInternal = "Provider=MSOLAP.5;Persist Security Info=True;Initial Catalog=
Microsoft_SQLServer_AnalysisServices;Data Source=$Embedded$;MDX
Compatibility=1;Safety Options=2;ConnectTo=11.0;MDX Missing Member
Mode=Error;Optimize Response=3;Cell Error Mode=TextValue"
Connection = Dispatch('ADODB.Connection')
Connection.Open(ConnStringInternal)
我希望可以初始化 Excel 的实例,然后初始化 PowerPivot 模型,然后使用 Excel 用于嵌入 PowerPivot 数据的内部连接字符串创建连接(类似于如何将 powerpivot 数据作为表格复制到 Excel 工作簿中? https://stackoverflow.com/a/33580647/5803031- 请注意,连接字符串与我在其他地方使用的不同)。不幸的是,这不起作用,我的猜测是 Python 在单独的实例中启动 ADODB.Connection 进程(因为当我在没有首先初始化 Excel 的情况下执行最后三行时收到相同的错误消息等):
com_error: (-2147352567, 'Exception occurred.', (0, u'Microsoft OLE DB Provider for SQL
Server 2012 Analysis Services.', u'Either the user, ****** (masked), does not have access
to the Microsoft_SQLServer_AnalysisServices database, or the database does not exist.',
None, 0, -2147467259), None)