SQL2005CLR函数扩展-深入环比计算的详解_mssql2005

此类问题还可以延伸到类似进销存的批次计算中,这也要关注其他历史记录来决定当前某条记录的状态。

sql语句无法简单实现mdx语句的类似功能,必须得用交叉表关联来对比。这里我们用CLR函数来实现mdx语句的类似语法。在select的时候把得到过的做个缓存就可以了。效率应该可以提高不少。

clr的代码如下,编译为TestFun.dll,复制到sql服务器的文件目录下。
--------------------------------------------------------------------------------

复制代码 代码如下:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public partial class UserDefinedFunctions
{

    // 保存当前组当前值
    private static System.Collections.Generic.Dictionary <string , SqlString > _listValue = new System.Collections.Generic.Dictionary <string , SqlString >();
    // 保存当前组
    private static System.Collections.Generic.Dictionary <string , string > _listGroup  = new System.Collections.Generic.Dictionary <string , string >();

    /// <summary>
    /// 获取当前组上条记录数值
    /// </summary>
    /// <param name="key"> 并发键 </param>
    /// <param name="currentGroup"> 当前组 </param>
    /// <param name="currentValue"> 当前组当前值 </param>
    /// <returns></returns>
    [Microsoft.SqlServer.Server.SqlFunction ]
    public static SqlString GetPrevMemberValue(SqlString key,SqlString currentGroup,SqlString currentValue)
    {
        if (key.IsNull || currentGroup.IsNull) return SqlString .Null;

      
        try
        {
            SqlString prevMemberValue = _listValue[key.Value];

            // 组变更
            if (_listGroup[key.Value] != currentGroup.Value)
            {
                prevMemberValue = SqlString .Null;
                _listGroup[key.Value] = currentGroup.Value;
             }
            // 值变更
            _listValue[key.Value] = currentValue;

            return prevMemberValue;
        }
        catch
        {
            return SqlString .Null;
        }
    }
    /// <summary>
    /// 初始化并发键
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    [Microsoft.SqlServer.Server.SqlFunction ]
    public static SqlBoolean InitKey(SqlString key)
    {
        try
        {
            _listValue.Add(key.Value, SqlString .Null);
            _listGroup.Add(key.Value, string .Empty);
            return true ;
        }
        catch
        {
            return false ;
        }
    }
    /// <summary>
    /// 释放并发键
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    [Microsoft.SqlServer.Server.SqlFunction ]
    public static SqlBoolean DisposeKey(SqlString key)
    {
        try
        {
            _listValue.Remove(key.Value);
            _listGroup.Remove(key.Value);
            return true ;
        }
        catch
        {
            return false ;
        }
    }
};

--------------------------------------------------------------------------------
部署和生成自定义函数,其中考虑到并发,我们还是需要一个并发键来表达当前查询
--------------------------------------------------------------------------------

复制代码 代码如下:

CREATE ASSEMBLY TestForSQLCLR FROM 'E:/sqlclrdata/TestFun.dll' WITH PERMISSION_SET = UnSAFE;
--
go
CREATE FUNCTION dbo. xfn_GetPrevMemberValue 
(  
    @key nvarchar ( 255),
    @initByDim nvarchar ( 255),
    @currentValue nvarchar ( 255)
)    
RETURNS nvarchar ( 255)
AS EXTERNAL NAME TestForSQLCLR. [UserDefinedFunctions]. GetPrevMemberValue
go
CREATE FUNCTION dbo. xfn_initKey
(  
    @key nvarchar ( 255)
)    
RETURNS bit
AS EXTERNAL NAME TestForSQLCLR. [UserDefinedFunctions]. InitKey
go
CREATE FUNCTION dbo. xfn_disposeKey 
(  
    @key nvarchar ( 255)
)    
RETURNS bit
AS EXTERNAL NAME TestForSQLCLR. [UserDefinedFunctions]. DisposeKey

--------------------------------------------------------------------------------
这样我们就可以使用了,测试脚本如下, xfn_GetPrevMemberValue就是获取上月价格的函数。
--------------------------------------------------------------------------------
-- 建立测试环境

复制代码 代码如下:

declare @t table (
    [ 区域 ] [varchar]( 4) COLLATE Chinese_PRC_CI_AS NULL,
    [TradeMonth] [varchar]( 7) COLLATE Chinese_PRC_CI_AS NULL,
    [TradeMoney] [float] NULL,
    [TradeArea] [float] NULL,
    [TradePrice] [float] NULL
)
insert into @t
select ' 闵行 ' , '2007-03' , '2125714.91' , '241.65' , '8796.67' union
select ' 闵行 ' , '2007-04' , '8408307.64' , '907.32' , '9267.19' union
select ' 闵行 ' , '2007-05' , '10230321.95' , '1095.88' , '9335.26' union
select ' 浦东 ' , '2007-01' , '12738432.25' , '1419.05' , '8976.73' union
select ' 浦东 ' , '2007-02' , '4970536.74' , '395.49' , '12568.05' union
select ' 浦东 ' , '2007-03' , '5985405.76' , '745.94' , '8023.98' union
select ' 浦东 ' , '2007-04' , '21030788.61' , '1146.89' , '18337.23' union
select ' 普陀 ' , '2007-01' , '1863896' , '161.39' , '11549.02' union
select ' 普陀 ' , '2007-02' , '1614015' , '119.59' , '13496.24' union
select ' 普陀 ' , '2007-03' , '1059235.19' , '135.21' , '7834'

 
-- 测试语句

复制代码 代码如下:

declare @key varchar ( 40)
declare @b bit

set @key= newid ()
select @b= dbo. xfn_initKey( @key)

select 区域 , TradeMonth, TradePrice, LastMonthPrice,
cast ( round (( Tradeprice- LastMonthPrice)* 100/ LastMonthPrice, 2) as varchar ( 10))+ '%' as 环比 from (
select *, cast ( dbo. xfn_GetPrevMemberValue( @key, 区域 , Tradeprice) as float ) as LastMonthPrice from @t
) t
select @b= dbo. xfn_disposeKey( @key)

 
-- 结果
/*
区域   TradeMonth TradePrice             LastMonthPrice         环比
---- ---------- ---------------------- ---------------------- -----------
闵行   2007-03    8796.67                NULL                   NULL
闵行   2007-04    9267.19                8796.67                5.35%
闵行   2007-05    9335.26                9267.19                 0.73%
浦东   2007-01    8976.73                NULL                   NULL
浦东   2007-02    12568.05               8976.73                40.01%
浦东   2007-03    8023.98                12568                  -36.16%
浦东   2007-04    18337.23                8023.98                128.53%
普陀   2007-01    11549.02               NULL                   NULL
普陀   2007-02    13496.24               11549                  16.86%
普陀   2007-03    7834                   13496.2                -41.95%
*/
--------------------------------------------------------------------------------
这个函数写的还是比较粗糙,如果进一步改进还可以详细定义如何获取上一个维度的方法。这里只是根据查询顺序来做缓存。感兴趣的朋友可以完善一下。

时间: 2024-10-11 18:39:58

SQL2005CLR函数扩展-深入环比计算的详解_mssql2005的相关文章

SQL2005CLR函数扩展-深入环比计算的详解

环比就是本月和上月的差值所占上月值的比例.在复杂的olap计算中我们经常会用到同比环比等概念,要求的上个维度的某个字段的实现语句非常简练,比如ssas的mdx语句类似[维度].CurrentMember.Prevmember就可以了   此类问题还可以延伸到类似进销存的批次计算中,这也要关注其他历史记录来决定当前某条记录的状态. sql语句无法简单实现mdx语句的类似功能,必须得用交叉表关联来对比.这里我们用CLR函数来实现mdx语句的类似语法.在select的时候把得到过的做个缓存就可以了.效

System.Data.DataTable计算功能详解

using System; using System.ComponentModel; using System.Data; using System.Windows.Forms; namespace WindowsApplication1 ...{ public partial class Form1 : Form ...{ public Form1() ...{ InitializeComponent(); } private void button1_Click(object sender,

asp.net 函数的定义 返回值 调用方法详解说明(vb.net/c#)

asp教程.net 函数的定义 返回值 调用方法详解说明(vb.net/c#),首页我们来看一个vb.net中开的asp.net教程创建一个函数的做法,如下 <script runat="server" language="VB">       Function getName() As String         Return "a"       End Function       Sub Page_Load(s As Obje

Linux时间时区、常用时间函数、整形时间计算思路详解

Linux时间时区详解与常用时间函数 时间与时区 整个地球分为二十四时区,每个时区都有自己的本地时间. Ø  UTC时间 与 GMT时间 我们可以认为格林威治时间就是时间协调时间(GMT = UTC),格林威治时间和UTC时间都用秒数来计算的. Ø  UTC时间与本地时间 UTC + 时区差 = 本地时间 时区差东为正,西为负.在此,把东八区时区差记为 +0800 UTC + (+0800) = 本地(北京)时间 Ø  UTC与Unix时间戳 在计算机中看到的UTC时间都是从(1970年01月0

C++中函数模板(function template) 的 重载(overload) 详解

函数模板(function template)重载, 即实例化特定的模板, 确定T的类型, 选择匹配度最高的一个; 需要注意传递的具体类型, 如传递的是"&s", 则表示"string* t = &s", 即实际匹配的类型为"string* t"; 当非函数模板和函数模板匹配度相同时, 优先选择非函数模板; 调用模板时, 一定要注意顺序, 或者提前声明, 以保证可以找到函数模板, 进行实例化; 具体参见代码注释, 代码如下: /*

php函数重载的替代方法--伪重载详解_php实例

函数重载的替代方法-伪重载,下面看一个具体的实例代码. <? php //函数重载的替代方法-伪重载 // //确实,在PHP中没有函数重载这个概念,让很多时候我们无法进行一些处理,甚至有时候不得不在函数后面定义好N个参数 //在看到了func_get_arg,func_get_args,func_num_args,这三个函数的时候,你们是不是想起了什么? function testOne ( $a ) { echo (' 一个参数就这样 '); } function testTwo ( $a

SQL2005CLR函数扩展-繁简转换的实现代码

这个方法比较简单,用Microsoft.VisualBasic命名空间下强大的字符串处理函数就可以了c#代码如下,编译为BigConvertor.dll-------------------------------------------------------------------------------- 复制代码 代码如下: using System; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; public

SQL2005CLR函数扩展-解析天气服务的实现

我们可以用CLR获取网络服务 来显示到数据库自定函数的结果集中,比如163的天气预报http://news.163.com/xml/weather.xml他的这个xml结果的日期是不正确的,但这个我们暂不讨论.从这个xml获取天气的CLR代码如下,用WebClient访问一下就可以了.然后通过Dom对象遍历节点属性返回给结果集. -------------------------------------------------------------------------------- 复制代

SQL2005CLR函数扩展-繁简转换的实现代码_mssql2005

这个方法比较简单,用Microsoft.VisualBasic命名空间下强大的字符串处理函数就可以了c#代码如下,编译为BigConvertor.dll-------------------------------------------------------------------------------- 复制代码 代码如下: using System; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; public