微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SQLSERVER2000 用过程来模拟MDX分析报表的效果(1)

这个想法的产生比较特殊,当时我在某学会工作,我对数据仓库的学习也初见成效,也做了一两个基于数据仓库的产品,总觉得数据仓库部署比较麻烦,而我的客户仅仅是需要一张分析型的报表.他只要满足多维的旋转,聚合,产生一个层次性的报表就可以满足要求.
     基于这种情况,我想:能不能在数据库下模拟一张这样的报表来满足用户的需要?
     因为写过仓库下的二个基于WEB的展示组件,显示一个MDX返回的CellSet,无非就是分解各轴中的Members的Caption,再取各单元格的属性作为显示格式等.思路并不复杂,不过,因为要设置合并,过程还是比较复杂的.
     那如果,我在数据库中用存储过程返回一个类CellSet的DataTable,那么,不也就可以实现了模拟的效果了吗?
     好了,闲话不说了.看正题吧.

第一部分:相关的存储过程
这个过程的目的就是生成一个类MDX的CellSet的结果.
要解释这个过程,先说CellSet的结构.我觉得因为你在了解了CellSet的结构后,理解这个过程会更简单,而且,我这个过程的思路本身就是从CellSet中来.

1.Cellset 对象
表示多维查询的结果。它是从立方或其它单元集中选出的单元的集合

Connection                   '//AdomdClient.AdomdConnection连接对象
 |
 |-CellSet                   '//查询结果集.
   |
   |-Cell                    '//结果集中的单元
   |-Axes                    '//结果集的轴集合,
   |-ProPerties              '//提供者的 Cellset 信息,可用 Property 检索.

说明

使用直接、类似数组的访问来实现对 Cellset 中数据的检索。可以“深入”到特定的成员以获得该成员的数据。例如,下列代码将返回名为 cst 的单元集第一坐标轴第一位置中第一个成员的标题
cst.Axes(0).Positions(0).Members(0).Caption

在单元集中没有当前单元的概念,而是使用 Item 方法从单元集中检索指定的 Cell 对象。Item 方法的参数确定检索哪个单元。可以指定单元的唯一序号值。也可通过使用单元集

每个轴上的位置号来检索单元。

使用 Cellset 对象的集合、方法属性,可以:
通过设置它的 ActiveConnection 属性,使打开的连接与 Cellset 对象相关联。
使用 Open 方法执行并检索多维查询的结果。
使用 Item 方法从 Cellset 中检索 Cell。
使用 Axes 集合返回定义 Cellset 的 Axis 对象。
使用 Filteraxis 属性检索有关用于过滤 Cellset 中数据的维的信息。
使用 Source 属性返回或指定用于定义 Cellset 的查询
使用 State 属性返回 Cellset 的当前状态(打开、关闭、正在执行或正在连接)。
使用 Close 方法关闭打开的 Cellset。
使用标准的 ADO Properties 集合检索特定提供者的 Cellset 信息。

下面的这个函数就是将一个CellSet转为一个DataTable,从源程序来,有删节.

    ''' <summary>
    ''' 将CellSet转为DataTable.
    ''' </summary>
    ''' <param name="CellSet">CellSet对象.</param>
    ''' <returns>DataTable</returns>
    ''' <remarks></remarks>
    Private Function AdoMdCellSetToDataTable(ByVal CellSet As Microsoft.analysisservices.AdomdClient.CellSet) As DataTable

        Dim Dt As New DataTable
        Dim Dc As New DataColumn
        Dim Dr As DaTarow = nothing
        Dim I As Int32
        Dim ColName As String = ""
        Dim sC As Int32
        Dim sR As Int32 = 0
        Dim RowID As Int32 = 0
        Dim SDr As DaTarow = nothing

        sC = 1
        For Each M As Microsoft.analysisservices.AdomdClient.Member In CellSet.Axes(1).Positions(0).Members
            sC += 1
            Dc = New DataColumn()
            Dc.ColumnName = Microsoft.VisualBasic.Space(sC) '//以空填充空白部分.
            Dt.Columns.Add(Dc)
        Next

        '//生成数据列对象
        sR = 0
        Dim R,C As Int32
        Dim ColID As Int16 = 0
        Dim AxexCount_0 As Int32 = CellSet.Axes(0).Positions.Count
        Dim AxexCount_1 As Int32 = CellSet.Axes(1).Positions.Count
        Dim CName As String

        R = 0 : C = 0
        For Each P As Microsoft.analysisservices.AdomdClient.Position In CellSet.Axes(0).Positions '//分解0轴,Mdx中的 ON Columns 轴.
            CName = ""
            R = 0 : ColID += 1
            For Each M As Microsoft.analysisservices.AdomdClient.Member In P.Members
                If R = 0 Then
                    CName = CName & "[" & Trim$(M.Caption) & "]"
                Else
                    CName = CName & ".[" & Trim$(M.Caption) & "]"
                End If

                R += 1
            Next
            Dc = New DataColumn()
            Dc.ColumnName = CName
            Dt.Columns.Add(Dc)
            C += 1
        Next

        '//添加行数据
        Dim CellVal As String
        Dim Pos As Int32 = 0
        Dim Ts As String
        Dim Cid As Int32

        For Each py As Microsoft.analysisservices.AdomdClient.Position In CellSet.Axes(1).Positions  '//分解1轴,Mdx中的 ON Rows 轴
            Dr = Dt.NewRow()
            RowID += 1
            I = 0
            '//行方向的名称列.
            For Each m As Microsoft.analysisservices.AdomdClient.Member In py.Members
                Ts = m.Caption
                Cid = I
                Dr(Cid) = Ts
                I += 1
            Next

            '//行数据
            For X As Int32 = 1 To AxexCount_0
                CellVal = "" & CellSet(Pos).FormattedValue
                If CellVal = "1.#INF" OrElse CellVal = "-1.#IND" OrElse CellVal = "1#I.NF0" OrElse CellVal = "1#I.NF0%" Then CellVal = "" 
                Dr(Cid+X) = CellVal
                Pos += 1
            Next
            Dt.Rows.Add(Dr)
        Next
        Return Dt

    End Function

 


效果:

 

 

观察上图,发现了什么,原来DataTable与CellSet是很象的.实质上,他们之间是可以通过前台的应用程序来转化,你如果将上图的DaTable 按 "].[" 来分解,按层合并相同项,DataTable也可以变成一个CellSet,有了这个思路,就可以写一个存储过程,将数据库中的数据按你的要求组织成要求的格式.将列的名称自定义的分隔符分隔,就可以达到相同的目的了.
下面的sql过程就实现了这个目的.自定义的分隔符是 "$@".

效果:

 

/***********************************************************
--调用例子
EXECUTE Prc_CoRSSReport_V2 N'test_data',
    N'海关名称,洲名称,地区名称',
    N'商品名称,年,月',
    N'金额',' WHERE 海关编号 between ''01'' and ''02''   and 时间编号 between 20070401 and 20070401  and 类编号=''10000002'''
***********************************************************/

CREATE PROC Prc_CoRSSReport_V2 (
------------------------------------------------------
--- 模拟 MDX V2.0 版.
---          MSTOP 2008/3/21
------------------------------------------------------
    @nvr_TableName nvarchar(128),
    @nvr_OnRows  nvarchar(1024),  --行列表
    @nvr_OnColumns nvarchar(1024),  --列列表
    @nvr_OnValue nvarchar(64),  --值字段
    @nvr_Where  nvarchar(1024)='' --条件
) AS BEGIN

    DECLARE @NVR_CMD NVARCHAR(1024)
    DECLARE @NVR_Columns NVARCHAR(1024)
    DECLARE @NVR_TmpTableName NVARCHAR(128)
    DECLARE @NVR_NewColName varchar(16)
    DECLARE @nvr_sOnRows NVARCHAR(1024)
    DECLARE @nvr_OnRows_B NVARCHAR(1024)
    DECLARE @nvr_OnColumns_B nvarchar(1024)
    DECLARE @NVR_sqlCOM_00 NVARCHAR(4000)

    SET @nvr_OnRows_B=N'[' + REPLACE(@nvr_OnRows,N',',N'],[') + N']'
    SET @nvr_OnColumns_B=N'[' + REPLACE(@nvr_OnColumns,[') + N']'

    SET @nvr_sOnRows=@nvr_OnRows
    SET @NVR_NewColName=N'Val_' + LEFT(REPLACE(NEWID(),'-',''),6)
    SET @NVR_TmpTableName=N'@TAB_TABLE'
    --提取数据到表变量中.
    SET @NVR_sqlCOM_00=N'DECLARE ' + @NVR_TmpTableName + N' TABLE ([' + REPLACE(@nvr_OnRows,N'] VARCHAR(128),[') + N'] VARCHAR(128),[' + @NVR_NewColName

+ N'] VARCHAR(128),[' + @nvr_OnValue + N'] FLOAT PRIMARY KEY  (' + @nvr_OnRows_B + N',[' + @NVR_NewColName + N']))'
    --合并列的名称.分隔符为 $@,也可以指定其它的分隔符.
    SET @NVR_Columns=N'RTRIM([' + REPLACE(@nvr_OnColumns,N']) + ''$@''+RTRIM([') + N'])+''$@'''
    SET @NVR_sqlCOM_00=@NVR_sqlCOM_00 + CHAR(13) + N'INSERT INTO ' + @NVR_TmpTableName + N' SELECT ' +@nvr_OnRows_B + N',(' + @NVR_Columns + N') AS [' +

@NVR_NewColName + N'],SUM([' + @nvr_OnValue + N']) AS '
            + @nvr_OnValue + N' FROM ' + @nvr_TableName
            + @nvr_Where
            + N' GROUP BY ' + @nvr_OnColumns_B   + N',' +  @nvr_OnRows_B
            + N' ORDER BY ' + @nvr_OnRows_B  + CHAR(13)

    --因为动态生成sql语句很长,所以定义多个sql变量.
    DECLARE @NVR_XCOLNAME AS NVARCHAR(128)
    DECLARE @NVR_sql0 AS NVARCHAR(4000)
    DECLARE @NVR_sql1 AS NVARCHAR(4000)
    DECLARE @NVR_sql2 AS NVARCHAR(4000)
    DECLARE @NVR_sql3 AS NVARCHAR(4000)
    DECLARE @NVR_sql4 AS NVARCHAR(4000)
    DECLARE @NVR_sql5 AS NVARCHAR(4000)
    DECLARE @NVR_sql6 AS NVARCHAR(4000)
    DECLARE @NVR_sql7 AS NVARCHAR(4000)
    DECLARE @NVR_sql8 AS NVARCHAR(4000)
    DECLARE @NVR_sql9 AS NVARCHAR(4000)
    DECLARE @NVR_sql10 AS NVARCHAR(4000)
    DECLARE @NVR_sql11 AS NVARCHAR(4000)
    DECLARE @NVR_sql12 AS NVARCHAR(4000)
    DECLARE @NVR_sql13 AS NVARCHAR(4000)
    DECLARE @NVR_sql14 AS NVARCHAR(4000)
    DECLARE @NVR_sql15 AS NVARCHAR(4000)
    DECLARE @NVR_sql16 AS NVARCHAR(4000)
    DECLARE @NVR_sql17 AS NVARCHAR(4000)
    DECLARE @NVR_sql18 AS NVARCHAR(4000)
    DECLARE @NVR_sql19 AS NVARCHAR(4000)
    DECLARE @NVR_sql20 AS NVARCHAR(4000)
    DECLARE @INT_ID AS INT

    SET @NVR_XCOLNAME=''
    SELECT

@NVR_sql0='',@INT_ID=0,@NVR_sql0='',@NVR_sql1='',@NVR_sql2='',@NVR_sql3='',@NVR_sql4='',@NVR_sql5='',@NVR_sql6='',@NVR_sql7='',@NVR_sql8='',@NVR_sql9='',
       

@NVR_sql10='',@NVR_sql11='',@NVR_sql12='',@NVR_sql13='',@NVR_sql14='',@NVR_sql15='',@NVR_sql16='',@NVR_sql17='',@NVR_sql18='',@NVR_sql19='',@NVR_sql20=''
     
    DECLARE @INT_I INT
    DECLARE @NVR_FLDNAME NVARCHAR(4000)
   
    SET @NVR_sql0 = N' SELECT ' +  @nvr_OnRows_B
    SET @NVR_CMD=N'DECLARE CORSS_CURSOR CURSOR FOR SELECT disTINCT [' + @NVR_NewColName + N'] FROM (SELECT ' + @NVR_Columns + N' AS [' + @NVR_NewColName +

N'] FROM ' + @nvr_TableName + N' ' + @NVR_WHERE  + N' ) AS TIISHFURL ORDER BY [' + @NVR_NewColName + N'] FOR READ ONLY ' --生成游标
    EXECUTE (@NVR_CMD)
    OPEN CORSS_CURSOR
   
    WHILE (1=1)  BEGIN
        FETCH NEXT FROM CORSS_CURSOR INTO @NVR_XCOLNAME  --遍历游标,将列头信息放入变量@NVR_XCOLNAME
        IF (@@FETCH_STATUS <>0) BREAK
       
        SET @INT_ID=@INT_ID+1
        SET @NVR_XCOLNAME=REPLACE(@NVR_XCOLNAME,CHAR(39),CHAR(39)+CHAR(39))
       
        ------------------------------------------------------------------------------
        IF @INT_ID <=20
            SET @NVR_sql1 = @NVR_sql1 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF @INT_ID <=40
            SET @NVR_sql2 = @NVR_sql2 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=60
            SET @NVR_sql3 = @NVR_sql3 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=80
            SET @NVR_sql4 = @NVR_sql4 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=100
            SET @NVR_sql5 = @NVR_sql5 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=120
            SET @NVR_sql6 = @NVR_sql6 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=140
            SET @NVR_sql7 = @NVR_sql7 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=160
            SET @NVR_sql8 = @NVR_sql8 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=180
            SET @NVR_sql9 = @NVR_sql9 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END) AS

[' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=200
            SET @NVR_sql10 = @NVR_sql10 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=220
            SET @NVR_sql11 = @NVR_sql11 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=240
            SET @NVR_sql12 = @NVR_sql12 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=260
            SET @NVR_sql13 = @NVR_sql13 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=280
            SET @NVR_sql14 = @NVR_sql14 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=300
            SET @NVR_sql15 = @NVR_sql15 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=320
            SET @NVR_sql16 = @NVR_sql16 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=340
            SET @NVR_sql17 = @NVR_sql17 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=360
            SET @NVR_sql18 = @NVR_sql18 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=380
            SET @NVR_sql19 = @NVR_sql19 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
        ELSE IF  @INT_ID <=400
            SET @NVR_sql20 = @NVR_sql20 + N',SUM(CASE [' + @NVR_NewColName + N'] WHEN ''' + @NVR_XCOLNAME + N''' THEN [' + @nvr_OnValue + N'] ELSE NULL END)

AS [' + @NVR_XCOLNAME + N']' --构造查询
    END -- WHILE (1 = 1)
    Close CORSS_CURSOR
    DEALLOCATE CORSS_CURSOR

    EXECUTE ( @NVR_sqlCOM_00 + @NVR_sql0 + @NVR_sql1 + @NVR_sql2  + @NVR_sql3 + @NVR_sql4 + @NVR_sql5 + @NVR_sql6 + @NVR_sql7 + @NVR_sql8 + @NVR_sql9
     + @NVR_sql10 + @NVR_sql11 + @NVR_sql12  + @NVR_sql13 + @NVR_sql14 + @NVR_sql15 + @NVR_sql16 + @NVR_sql17 + @NVR_sql18 + @NVR_sql19 + @NVR_sql20
     + N' FROM ' + @NVR_TmpTableName + N' GROUP BY ' + @nvr_OnRows ) -- 执行
    RETURN 0 --释放游标,返回0表示成功

End

GO

 

来一张最终效果,否则你们没兴趣看了. 哈哈...

 

 

sqlSERVER2000 用过程来模拟MDX分析报表的效果(2)

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mstop/archive/2008/10/11/3058767.aspx

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐