当我不得不使用Python从PowerPivot模型中读取一些数据时,看起来像是一项微不足道的任务变成了一场真正的噩梦 . 我相信我在过去的几天里对此进行了很好的研究,但现在我遇到了一堵砖墙,并希望得到Python / SSAS / ADO社区的一些帮助 .
基本上,我想要的是以编程方式访问存储在PowerPivot模型中的原始数据 - 我的想法是通过下面列出的方法之一连接到底层的PowerPivot(即MS Analysis Services)引擎,列出模型中包含的表,然后使用简单的DAX查询(类似于 EVALUATE (table_name)
)从每个表中提取原始数据 . 容易腻,对吗?好吧,也许不是 .
0.一些背景资料
如您所见,我尝试了几种不同的方法 . 我会尝试尽可能仔细地记录所有内容,以便那些不熟悉PowerPivot功能的人会很清楚我想做什么 .
首先,有关编程访问Analysis Services引擎的一些背景知识(它表示2005 SQL Server,但它应该仍然适用):SQL Server Data Mining Programmability和Data providers used for Analysis Services connections .
我将在下面的示例中使用的示例Excel / PowerPivot文件可在此处找到:Microsoft PowerPivot for Excel 2010 and PowerPivot in Excel 2013 Samples .
另请注意,我使用的是Excel 2010,因此我的一些代码是特定于版本的 . 例如 . 如果您使用的是Excel 2013, wb.Connections["PowerPivot Data"].OLEDBConnection.ADOConnection
应为 wb.Model.DataModelConnection.ModelConnection.ADOConnection
.
我将在整个问题中使用的连接字符串基于以下信息:Connect to PowerPivot engine with C# . 另外,一些方法显然需要在数据检索之前对PowerPivot模型进行某种初始化 . 见这里:Automating PowerPivot Refresh operation from VBA .
最后,这里有几个链接显示这应该是可以实现的(但请注意,这些链接主要是指C#,而不是Python):
-
Made connection to PowerPivot DataModel, how can I fill a dataset with it?
-
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()
这类似于What's the simplest way to access mssql with python or ironpython? . 不幸的是,这也行不通:
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)
与Opposite 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的博客文章:Export a table or DAX query from Power Pivot to CSV using VBA . 请注意,此方法使用显式刷新命令来初始化模型(即"server") . 这是错误消息:
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连接已经 Build :
-
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)
与Connection to Access from Python [duplicate]和Query access using ADO in Win32 platform (Python recipe)相似 . 不幸的是,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数据的内部连接字符串创建连接(类似于How do you copy the powerpivot data into the excel workbook as a table? - 请注意,连接字符串不同于我've used elsewhere). Unfortunately, this doesn'工作,我的猜测是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)
3 回答
瞧,我终于设法解决了这个问题 - 事实证明使用Python访问Power Pivot数据确实是可能的!下面是我所做的简短回顾 - 你可以在这里找到更详细的描述:Analysis Services (SSAS) on a shoestring . 注意:代码已经过优化,无论是效率还是优雅 .
安装Microsoft Power BI桌面(附带免费的Analysis Services服务器,因此不需要昂贵的SQL Server许可证 - 但是,如果您拥有适当的许可证,相同的方法显然也可以使用) .
首先创建msmdsrv.ini设置文件,然后从ABF文件(使用AMO.NET)恢复数据库,然后使用ADOMD.NET提取数据,启动AS引擎 .
这是说明AS引擎AMO.NET部分的Python代码:
而数据提取部分:
然后通过以下方式提取原始数据:
从PowerPivot获取数据的问题在于,PowerPivot中的表格引擎在Excel内部运行,并且连接到该引擎的方式也是让您的代码在Excel中运行 . (我怀疑它可能使用共享内存或其他一些传输,但它肯定不会侦听TCP端口或命名管道或类似的东西,这将允许外部进程连接)
我们通过在Excel中运行C#VSTO Excel加载项在Dax Studio中执行此操作 . 但是,它仅用于测试分析查询,而不是用于批量数据提取 . 我们使用字符串变量编组来自UI的加载项的数据,因此整个数据集必须小于2Gb或响应被截断,您将看到“无法识别的响应”错误(数据被序列化为XMLA行集)这是非常冗长的,所以当只提取几百Mb的数据时可能会看到它中断)
如果你想构建一个脚本来自动从模型中提取所有原始数据,我不相信你可以在Excel中运行进程内运行的python解释器 . 我会看看像这样的一个vba宏http://www.powerpivotblog.nl/export-a-table-or-dax-query-from-power-pivot-to-csv-using-vba/
您应该会发现可以使用类似“SELECT * FROM $ SYSTEM.DBSCHEMA_TABLES”的内容查询模型以获取表的列表 - 然后您可以遍历每个表并使用上述链接中的代码变体进行提取 .
我联系了Tom Gleeson(又名GobánSaor),他很友善地让我在这里发布他的电子邮件 . 其中有一些有趣的小块,所以希望其他人也会觉得它们很有用 .
Email #1
Email #2