Excel 更改PowerPivot文件中的连接数据

Excel 更改PowerPivot文件中的连接数据,excel,ms-office,powerpivot,Excel,Ms Office,Powerpivot,所以我遇到了一个有趣的问题。我需要在PowerPivot查询中指定一个自定义WHERE子句。我必须根据外部条件改变它。我想编辑文件并保存副本。你知道怎么做吗?我从二进制文件打开了PowerPivot文件,但它似乎是加密的…您可以转到现有连接,然后在那里进行更新。如果您再次打开相同的数据源(SQL、SSRS或任何其他),而不是更改现有连接上的参数,则会降低性能,因为PowerPivot会将这些数据源视为单独的连接。您可以转到现有连接,然后在那里进行更新。如果您再次打开相同的数据源(SQL、SSRS

所以我遇到了一个有趣的问题。我需要在PowerPivot查询中指定一个自定义WHERE子句。我必须根据外部条件改变它。我想编辑文件并保存副本。你知道怎么做吗?我从二进制文件打开了PowerPivot文件,但它似乎是加密的…

您可以转到现有连接,然后在那里进行更新。如果您再次打开相同的数据源(SQL、SSRS或任何其他),而不是更改现有连接上的参数,则会降低性能,因为PowerPivot会将这些数据源视为单独的连接。

您可以转到现有连接,然后在那里进行更新。如果您再次打开相同的数据源(SQL、SSRS或任何其他),而不是更改现有连接上的参数,则会降低性能,因为PowerPivot会将这些数据源视为单独的连接。

解决方案是将Excel工作簿作为Zip打开(使用Package类)

如果要修改查询,可以。位于/xl/customData/item1.data的文件是一个备份文件,表示用于处理查询的PowerPivot数据库(它只是一个在Vertipaq模式下运行的Analysis Services数据库)。您需要将文件还原到在Vertipaq模式下运行的SSAS实例。完成后,将查询作为ALTER脚本编写脚本。修改脚本(在本例中,将@projectd替换为我的实际projectd),然后对数据库运行它们。完成所有这些操作后,备份数据库并将其放回Excel工作簿。这将修改查询

连接数据存储在/xl/connections.xml文件中。打开它,修改并替换。重新打包,现在又有了工作簿

这是我写的代码。您必须根据需要调用这些方法。基本的想法是存在的,虽然

    const string DBName = "Testing";
    const string OriginalBackupPath = @"\\MyLocation\BKUP.abf";
    const string ModifiedBackupPath = @"\\MyLocation\BKUPAfter.abf";
    const string ServerPath = @"machineName\powerpivot";

    private static readonly Server srv = new Server();
    private static readonly Scripter scripter = new Scripter();
    private static Database db;

    private static byte[] GetPackagePartContents(string packagePath, string partPath)
    {
        var pack = Package.Open(packagePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
        var part = pack.GetPart(new Uri(partPath, UriKind.Relative));
        var stream = part.GetStream();
        var b = new byte[stream.Length];
        stream.Read(b, 0, b.Length);
        stream.Flush();
        stream.Close();
        pack.Flush();
        pack.Close();
        return b;
    }

    private static void WritePackagePartContents(string packagePath, string partPath, byte[] contents)
    {
        var uri = new Uri(partPath, UriKind.Relative);
        var pack = Package.Open(packagePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
        var part = pack.GetPart(uri);
        var type = part.ContentType;
        pack.DeletePart(uri);
        pack.CreatePart(uri, type);
        part = pack.GetPart(uri);
        var stream = part.GetStream();
        stream.Write(contents, 0, contents.Length);
        stream.Flush();
        stream.Close();
        pack.Flush();
        pack.Close();
    }

    private static void RestoreBackup(string server, string dbName, string backupPath)
    {
        srv.Connect(server);
        if (srv.Databases.FindByName(dbName) != null) { srv.Databases.FindByName(dbName).Drop(); srv.Update(); }
        srv.Restore(backupPath, dbName, true);
        srv.Update();
        srv.Refresh();
    }

    private static void WriteContentsToFile(byte[] contents, string filePath)
    {
        var fileStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write);
        fileStream.Write(contents, 0, contents.Length);
        fileStream.Flush();
        fileStream.Close();
    }

    private static byte[] ReadContentsFromFile(string filePath)
    {
        var fileStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write);
        var b = new byte[fileStream.Length];
        fileStream.Read(b, 0, b.Length);
        fileStream.Flush();
        fileStream.Close();
        return b;
    }

    private static XDocument GetAlterScript(MajorObject obj)
    {
        var stream = new MemoryStream();
        var streamWriter = XmlWriter.Create(stream);
        scripter.ScriptAlter(new[] { obj }, streamWriter, false);
        streamWriter.Flush();
        streamWriter.Close();
        stream.Flush();
        stream.Position = 0;
        var b = new byte[stream.Length];
        stream.Read(b, 0, b.Length);
        var alterString = new string(Encoding.UTF8.GetString(b).ToCharArray().Where(w => w != 65279).ToArray());
        var alter = XDocument.Parse(alterString);
        stream.Close();
        return alter;
    }

    private static void ExecuteScript(string script)
    {
        srv.Execute(script);
        srv.Update();
        db.Process();
        db.Refresh();
    }



    private static void ProcessPowerpointQueries(string bookUrl, string projectId)
    {
        byte[] b = GetPackagePartContents(bookUrl, "/xl/customData/item1.data");
        WriteContentsToFile(b, OriginalBackupPath);
        RestoreBackup(ServerPath, DBName, OriginalBackupPath);
        var db = srv.Databases.GetByName(DBName);
        var databaseView = db.DataSourceViews.FindByName("Sandbox");
        var databaseViewAlter = GetAlterScript(databaseView);
        var cube = db.Cubes.FindByName("Sandbox");
        var measureGroup = cube.MeasureGroups.FindByName("Query");
        var partition = measureGroup.Partitions.FindByName("Query");
        var partitionAlter = GetAlterScript(partition);
        var regex = new Regex(@"\s@projectid=\w*[ ,]");
        var newDatabaseViewAlter = databaseViewAlter.ToString().Replace(regex.Match(databaseViewAlter.ToString()).Value.Trim(',',' '), @"@projectid=" + projectId);
        ExecuteScript(newDatabaseViewAlter);
        var newPartitionAlter = partitionAlter.ToString().Replace(regex.Match(partitionAlter.ToString()).Value.Trim(',', ' '), @"@projectid=" + projectId);
        ExecuteScript(newPartitionAlter);
        db.Backup(ModifiedBackupPath, true);
        WritePackagePartContents(bookUrl, @"/xl/customData/item1.data", ReadContentsFromFile(ModifiedBackupPath));
        db.Drop();
        srv.Disconnect();
    }

    private static void ProcessWorkbookLinks(string bookUrl, string newCoreUrl)
    {
        var connectionsFile = GetPackagePartContents(bookUrl, @"/xl/connections.xml");
        var connectionsXml = Encoding.UTF8.GetString(connectionsFile);
        connectionsXml = connectionsXml.Replace(
            new Regex(@"Data Source=\S*;").Match(connectionsXml).Value.Trim(';'), @"Data Source=" + newCoreUrl);
        WritePackagePartContents(bookUrl, @"/xl/connections.xml", connectionsXml.Replace(@"https://server/site/", newCoreUrl).ToCharArray().Select(Convert.ToByte).ToArray());
    }

解决方案是将Excel工作簿作为Zip打开(使用Package类)

如果要修改查询,可以。位于/xl/customData/item1.data的文件是一个备份文件,表示用于处理查询的PowerPivot数据库(它只是一个在Vertipaq模式下运行的Analysis Services数据库)。您需要将文件还原到在Vertipaq模式下运行的SSAS实例。完成后,将查询作为ALTER脚本编写脚本。修改脚本(在本例中,将@projectd替换为我的实际projectd),然后对数据库运行它们。完成所有这些操作后,备份数据库并将其放回Excel工作簿。这将修改查询

连接数据存储在/xl/connections.xml文件中。打开它,修改并替换。重新打包,现在又有了工作簿

这是我写的代码。您必须根据需要调用这些方法。基本的想法是存在的,虽然

    const string DBName = "Testing";
    const string OriginalBackupPath = @"\\MyLocation\BKUP.abf";
    const string ModifiedBackupPath = @"\\MyLocation\BKUPAfter.abf";
    const string ServerPath = @"machineName\powerpivot";

    private static readonly Server srv = new Server();
    private static readonly Scripter scripter = new Scripter();
    private static Database db;

    private static byte[] GetPackagePartContents(string packagePath, string partPath)
    {
        var pack = Package.Open(packagePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
        var part = pack.GetPart(new Uri(partPath, UriKind.Relative));
        var stream = part.GetStream();
        var b = new byte[stream.Length];
        stream.Read(b, 0, b.Length);
        stream.Flush();
        stream.Close();
        pack.Flush();
        pack.Close();
        return b;
    }

    private static void WritePackagePartContents(string packagePath, string partPath, byte[] contents)
    {
        var uri = new Uri(partPath, UriKind.Relative);
        var pack = Package.Open(packagePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
        var part = pack.GetPart(uri);
        var type = part.ContentType;
        pack.DeletePart(uri);
        pack.CreatePart(uri, type);
        part = pack.GetPart(uri);
        var stream = part.GetStream();
        stream.Write(contents, 0, contents.Length);
        stream.Flush();
        stream.Close();
        pack.Flush();
        pack.Close();
    }

    private static void RestoreBackup(string server, string dbName, string backupPath)
    {
        srv.Connect(server);
        if (srv.Databases.FindByName(dbName) != null) { srv.Databases.FindByName(dbName).Drop(); srv.Update(); }
        srv.Restore(backupPath, dbName, true);
        srv.Update();
        srv.Refresh();
    }

    private static void WriteContentsToFile(byte[] contents, string filePath)
    {
        var fileStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write);
        fileStream.Write(contents, 0, contents.Length);
        fileStream.Flush();
        fileStream.Close();
    }

    private static byte[] ReadContentsFromFile(string filePath)
    {
        var fileStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write);
        var b = new byte[fileStream.Length];
        fileStream.Read(b, 0, b.Length);
        fileStream.Flush();
        fileStream.Close();
        return b;
    }

    private static XDocument GetAlterScript(MajorObject obj)
    {
        var stream = new MemoryStream();
        var streamWriter = XmlWriter.Create(stream);
        scripter.ScriptAlter(new[] { obj }, streamWriter, false);
        streamWriter.Flush();
        streamWriter.Close();
        stream.Flush();
        stream.Position = 0;
        var b = new byte[stream.Length];
        stream.Read(b, 0, b.Length);
        var alterString = new string(Encoding.UTF8.GetString(b).ToCharArray().Where(w => w != 65279).ToArray());
        var alter = XDocument.Parse(alterString);
        stream.Close();
        return alter;
    }

    private static void ExecuteScript(string script)
    {
        srv.Execute(script);
        srv.Update();
        db.Process();
        db.Refresh();
    }



    private static void ProcessPowerpointQueries(string bookUrl, string projectId)
    {
        byte[] b = GetPackagePartContents(bookUrl, "/xl/customData/item1.data");
        WriteContentsToFile(b, OriginalBackupPath);
        RestoreBackup(ServerPath, DBName, OriginalBackupPath);
        var db = srv.Databases.GetByName(DBName);
        var databaseView = db.DataSourceViews.FindByName("Sandbox");
        var databaseViewAlter = GetAlterScript(databaseView);
        var cube = db.Cubes.FindByName("Sandbox");
        var measureGroup = cube.MeasureGroups.FindByName("Query");
        var partition = measureGroup.Partitions.FindByName("Query");
        var partitionAlter = GetAlterScript(partition);
        var regex = new Regex(@"\s@projectid=\w*[ ,]");
        var newDatabaseViewAlter = databaseViewAlter.ToString().Replace(regex.Match(databaseViewAlter.ToString()).Value.Trim(',',' '), @"@projectid=" + projectId);
        ExecuteScript(newDatabaseViewAlter);
        var newPartitionAlter = partitionAlter.ToString().Replace(regex.Match(partitionAlter.ToString()).Value.Trim(',', ' '), @"@projectid=" + projectId);
        ExecuteScript(newPartitionAlter);
        db.Backup(ModifiedBackupPath, true);
        WritePackagePartContents(bookUrl, @"/xl/customData/item1.data", ReadContentsFromFile(ModifiedBackupPath));
        db.Drop();
        srv.Disconnect();
    }

    private static void ProcessWorkbookLinks(string bookUrl, string newCoreUrl)
    {
        var connectionsFile = GetPackagePartContents(bookUrl, @"/xl/connections.xml");
        var connectionsXml = Encoding.UTF8.GetString(connectionsFile);
        connectionsXml = connectionsXml.Replace(
            new Regex(@"Data Source=\S*;").Match(connectionsXml).Value.Trim(';'), @"Data Source=" + newCoreUrl);
        WritePackagePartContents(bookUrl, @"/xl/connections.xml", connectionsXml.Replace(@"https://server/site/", newCoreUrl).ToCharArray().Select(Convert.ToByte).ToArray());
    }

CamronBlue,感谢您提供这组代码。我现在正在努力实现它。我很难相信PowerPivot for Office 2010没有附带此功能。您是如何针对特定的Excel工作簿实际执行该代码的?你把它打包成COM对象还是什么?是否可以通过VBA执行与上面相同的操作?我对VBA比任何其他语言都熟悉。谢谢@Brad我在.NET库中实现了上述代码。我没有将其打包为COM,我不确定是否可以使用VBA。您可能需要做一些研究,看看是否可以打包为COM对象并从VBA调用。谢谢您的代码片段。我相信这会有帮助的。你能告诉我们
Server
Database
Scripter
这些课程是从哪里来的吗?它是官方API/库的一部分还是您编写的?谢谢。@Andreasader这些名称空间可能是Microsoft.SqlServer.Management.Smo或Microsoft.AnalysisServices名称空间。。。不记得到底是哪一个…@CamronBute:谢谢!它是Microsoft.AnalysisServices。不幸的是,这需要运行至少需要SQL Server标准的SQL Analysis Server。我正在寻找一种无需任何先决条件即可更改此数据的方法。CamronBlue,感谢您提供这组代码。我现在正在努力实现它。我很难相信PowerPivot for Office 2010没有附带此功能。您是如何针对特定的Excel工作簿实际执行该代码的?你把它打包成COM对象还是什么?是否可以通过VBA执行与上面相同的操作?我对VBA比任何其他语言都熟悉。谢谢@Brad我在.NET库中实现了上述代码。我没有将其打包为COM,我不确定是否可以使用VBA。您可能需要做一些研究,看看是否可以打包为COM对象并从VBA调用。谢谢您的代码片段。我相信这会有帮助的。你能告诉我们
Server
Database
Scripter
这些课程是从哪里来的吗?它是官方API/库的一部分还是您编写的?谢谢。@Andreasader这些名称空间可能是Microsoft.SqlServer.Management.Smo或Microsoft.AnalysisServices名称空间。。。不记得到底是哪一个…@CamronBute:谢谢!它是Microsoft.AnalysisServices。不幸的是,这需要运行至少需要SQL Server标准的SQL Analysis Server。我正在寻找一种无需任何先决条件即可更改此数据的方法。