MDX查询SSAS结果--通过adomd.net展示到客户端

SSAS多维模型建好之后,除了在excel客户端直接链接ssas源拖拽pivot分析使用外,还可以讲要展示的结果集通过MDX语句查询出来,嵌入到程序中,通过运行程序跑出完整的报表。如图所示:

MDX对于OLAP数据集就像Transact-SQL对于Microsoft SQL Server关系数据库。在SQL里mdxquery查询视窗,将SSAS的查询结果,显示在我们自定义的应用程序里面,和传统的ADO.net链接SQL数据库引擎相似。

例如如下MDX查询代码:

WITH MEMBER [Target] AS [Measures].[USD REV TARGET - Vw ST SUBREGION TGT]/1000 
                            MEMBER [QTD] AS [Measures].[ST AMT USD]/1000       
                            MEMBER [HitRate] AS IIF([Target]=NULL OR [Target]=0,NULL,[QTD]/[Target])
                            MEMBER [SO_Target] as [Measures].[USD REV TARGET]/1000   
                            MEMBER [SO_QTD] AS [Measures].[SO AMT USD]/1000                    
                            MEMBER [SO_HitRate] as IIF([SO_Target]=NULL OR [SO_Target]=0,NULL,[SO_QTD]/[SO_Target])    
                            SELECT CROSSJOIN([OverviewAllBrand-BU].[BU CODE],                    
                            {[Target],[QTD],[HitRate],[SO_Target],[SO_QTD],[SO_HitRate]}) ON COLUMNS,      
                            CROSSJOIN({[OverviewAllBrand-Region].[REGION EN], [OverviewAllBrand-Region].[REGION EN].CHILDREN },  
                            {[OverviewAllBrand-Channel].[CHANNEL TYPE].CHILDREN, [OverviewAllBrand-Channel].[CHANNEL TYPE] }) ON ROWS     
                            FROM [OverviewAllBrand]   where  ([OverviewAllBrand-Region].[AREA CN].&[CHINA])
View Code

原理:

1、客户端与SSAS的通讯,其实传递是XML/A指令。发起这种指令,可以通过标准的Web Request(封装为一个SOAP包即可),也可以通过客户端API。

2、SQL Server 自带了一个客户端API,Microsoft.AnalysisServices.AdomdClient.dll.这个程序集,一般是在 C:\Program Files (x86)\Microsoft.NET\ADOMD.NET\100\Microsoft.AnalysisServices.AdomdClient.dll 这个路径下面。所以首先项目程序中需要先引用这个dll。

使用Adomd的方式与标准的ADO.NET还是有相似之处的,也需要有Connection以及Command之类的对象,只不过它的查询语法是所谓的MDX(多维表达式),而且它返回的结果不是一个平面的二维结构,可能会有多个轴(最多可以有128个轴),所以解析的时候会更加复杂些。

以下是代码:

        public DataTable GetRegionOverview()
        {
            DataTable dt = null;
            string strSql = @"WITH MEMBER [Target] AS [Measures].[USD REV TARGET - Vw ST SUBREGION TGT]/1000 
                            MEMBER [QTD] AS [Measures].[ST AMT USD]/1000       
                            MEMBER [HitRate] AS IIF([Target]=NULL OR [Target]=0,NULL,[QTD]/[Target])
                            MEMBER [SO_Target] as [Measures].[USD REV TARGET]/1000   
                            MEMBER [SO_QTD] AS [Measures].[SO AMT USD]/1000                    
                            MEMBER [SO_HitRate] as IIF([SO_Target]=NULL OR [SO_Target]=0,NULL,[SO_QTD]/[SO_Target])    
                            SELECT CROSSJOIN([OverviewAllBrand-BU].[BU CODE],                    
                            {[Target],[QTD],[HitRate],[SO_Target],[SO_QTD],[SO_HitRate]}) ON COLUMNS,      
                            CROSSJOIN({[OverviewAllBrand-Region].[REGION CN], [OverviewAllBrand-Region].[REGION CN].CHILDREN },  
                            {[OverviewAllBrand-Channel].[CHANNEL TYPE].CHILDREN, [OverviewAllBrand-Channel].[CHANNEL TYPE] }) ON ROWS     
                            FROM [OverviewAllBrand]   where  ([OverviewAllBrand-Region].[AREA CN].&[CHINA])";
            DataTable ssasResult = base.GetSsasResult(strSql);
            if (ssasResult.Rows.Count > 2)
            {
                int num;
                ssasResult.Rows[0][2] = " All Sell Thru Rev (K$) ";
                ssasResult.Rows[0][3] = " All Sell Thru Rev (K$) ";
                ssasResult.Rows[0][4] = " All Sell Thru Rev (K$) ";
                ssasResult.Rows[0][5] = " All Sell Out Rev (K$) ";
                ssasResult.Rows[0][6] = " All Sell Out Rev (K$) ";
                ssasResult.Rows[0][7] = " All Sell Out Rev (K$) ";
                ssasResult.Rows[1][5] = " Target ";
                ssasResult.Rows[1][6] = " QTD ";
                ssasResult.Rows[1][7] = " HitRate ";
                ssasResult.Rows[1][0] = " Region ";
                ssasResult.Rows[1][1] = " Channel ";
                for (num = 0; num < ssasResult.Rows.Count; num++)
                {
                    if (ssasResult.Rows[num][0].ToString().ToLower() == "all")
                    {
                        ssasResult.Rows[num][0] = " ACCN ";
                    }
                    if (ssasResult.Rows[num][1].ToString().ToLower() == "all")
                    {
                        if (ssasResult.Rows[num][0].ToString().Trim().ToUpper() == "ACCN")
                        {
                            ssasResult.Rows[num][1] = " ACCN Total ";
                        }
                        else
                        {
                            ssasResult.Rows[num][1] = " Sub Total ";
                        }
                    }
                }
            return ssasResult;
        }
View Code

BaseDBAccess.cs  

使用标准的方法:CellSet2DataTable(CellSet cs)返回一个特殊的CellSet对象,因为SSAS的结果集可能是有多维的 ,在方法中将CellSet转换为DataTable;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.AnalysisServices.AdomdClient;
using System.Data;

namespace ReportExcel.DataAccess
{
    public class BaseDBAccess
    {
        private AdomdConnection conn;
        private string connStr = string.Empty;

        protected BaseDBAccess()
        {

        }

        /// <summary>
        /// 设置连接的SSAS数据库
        /// </summary>
        /// <param name="strConn"></param>
        protected void SetSSASDB(string strConn)
        {
            //connStr = "Provider=MSOLAP; DataSource=http://10.40.15.82/olap/msmdpump.dll; Initial Catalog=" + strConn;
            connStr = "Provider=MSOLAP; DataSource=http://10.40.15.87/olap/msmdpump.dll; Initial Catalog=" + strConn;
        }

        /// <summary>
        /// 选择连接的SSAS数据库
        /// </summary>
        /// <param name="strDB"></param>
        private void CreateConn()
        {
            conn = new AdomdConnection(connStr);
            conn.Open();
        }

        /// <summary>
        /// 到SSAS去查询数据,缺省连接SSAS1数据库
        /// </summary>
        /// <param name="strSql"></param>
        /// <returns></returns>
        protected DataTable GetSsasResult(string strSql)
        {
            CreateConn();
            AdomdCommand command = conn.CreateCommand();
            command.CommandText = strSql;
            CellSet cs = command.ExecuteCellSet();
            conn.Close();
            return CellSet2DataTable(cs);
        }

        /// <summary>
        /// 将CellSet转换为DataTable
        /// </summary>
        /// <param name="cs"></param>
        /// <returns></returns>
        private DataTable CellSet2DataTable(CellSet cs)
        {
            DataTable dt = new DataTable();
            DataColumn dc = new DataColumn();
            DataRow dr = null;
            int rowDescCount = 0;
            int rowColLayersCount = 0;
            if (cs.Axes[1].Set.Tuples.Count > 0)
            {
                rowDescCount = cs.Axes[1].Set.Tuples[0].Members.Count;  //得到行描述的列数
            }
            if (cs.Axes[0].Set.Tuples.Count > 0)
            {
                rowColLayersCount = cs.Axes[0].Set.Tuples[0].Members.Count;  //得到Axis[0]表头的层数
            }

            //根据纵向表头的层数生成Columns
            for (int i = 0; i < rowDescCount; i++)
            {
                dt.Columns.Add(new DataColumn("c" + i.ToString()));
            }

            //生成剩下所有的Columns
            string name;
            for (int i = 0; i < cs.Axes[0].Set.Tuples.Count; i++)
            {
                dc = new DataColumn();
                name = "a" + i.ToString();
                dc.ColumnName = name;
                dc.DataType = typeof(object);
                dt.Columns.Add(dc);
            }

            //每层表头生成一行数据
            for (int i = 0; i < rowColLayersCount; i++)
            {
                dr = dt.NewRow();
                for (int j = 0; j < dt.Columns.Count - rowDescCount; j++)
                {
                    dr[j + rowDescCount] = cs.Axes[0].Set.Tuples[j].Members[i].Caption;
                }
                dt.Rows.Add(dr);
            }

            //生成剩下的所有的数据行,以及纵向表头的描述
            if (cs.Axes[1].Set.Tuples.Count > 0)
            {
                for (int i = 0; i < cs.Axes[1].Set.Tuples.Count; i++)
                {
                    dr = dt.NewRow();
                    //维度描述列数据(行头)
                    name = "";
                    for (int j = 0; j < cs.Axes[1].Set.Tuples[i].Members.Count; j++)
                    {
                        dr[j] = cs.Axes[1].Set.Tuples[i].Members[j].Caption;
                    }
                    dt.Rows.Add(dr);
                }

                //填充数据
                for (int i = 0; i < dt.Rows.Count - rowColLayersCount; i++)
                {
                    for (int j = rowDescCount; j < dt.Columns.Count; j++)
                    {
                        dt.Rows[i + rowColLayersCount][j] = cs.Cells[j - rowDescCount, i].Value;
                    }
                }
            }

            dt.TableName = "SSAS Data";
            return dt;
        }
    }
}
View Code

 如有兴趣可以参见另一篇其他博友bloger的文章,比较完整的一个winform小程序:

http://www.cnblogs.com/chenxizhang/archive/2011/05/28/2061073.html

posted @ 2016-08-31 12:07  依旧一生有你  阅读(1222)  评论(0编辑  收藏  举报