SQL2005CLR函数扩展-环比计算

      环比就是本月和上月的差值所占上月值的比例。在复杂的olap计算中我们经常会用到同比环比等概念,要求的上个维度的某个字段的实现语句非常简练,比如ssas的mdx语句类似[维度].CurrentMember.Prevmember就可以了。此类问题还可以延伸到类似进销存的批次计算中,这也要关注其他历史记录来决定当前某条记录的状态。

 

     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%

 

*/

 


 

这个函数写的还是比较粗糙,如果进一步改进还可以详细定义如何获取上一个维度的方法。这里只是根据查询顺序来做缓存。感兴趣的朋友可以完善一下。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 SQL Server 中进行 HTTP 请求,可以使用 CLR (Common Language Runtime)。CLR 是一种可在 SQL Server 中运行的 .NET 程序。 下面是一个示例,演示如何使用 CLR 和 HTTPWebRequest 类从 SQL Server 中发出 HTTP GET 请求: 1. 首先,需要创建一个新的 C# 类库项目,添加对 System.Net 和 System.Data.SqlServerCe 的引用。然后编写以下代码: ```csharp using System; using System.Data.SqlTypes; using System.IO; using System.Net; using System.Text; using Microsoft.SqlServer.Server; public partial class HttpRequests { [Microsoft.SqlServer.Server.SqlFunction(DataAccess = DataAccessKind.Read)] public static SqlString GetRequest(SqlString url) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url.Value); request.Method = "GET"; request.ContentType = "application/json"; try { using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (Stream stream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(stream)) { string result = reader.ReadToEnd(); return result; } } } } catch (WebException ex) { using (HttpWebResponse response = (HttpWebResponse)ex.Response) { if (response == null) { return new SqlString(ex.Message); } else { using (Stream stream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(stream)) { return reader.ReadToEnd(); } } } } } } } ``` 2. 编译并部署 CLR 程序集到 SQL Server 中。 3. 在 SQL Server 中创建一个新的存储过程,可以使用以下代码: ```sql CREATE PROCEDURE dbo.GetHttpData @url NVARCHAR(MAX), @result NVARCHAR(MAX) OUTPUT AS EXTERNAL NAME HttpRequests.[HttpRequests.HttpRequests].GetRequest; ``` 4. 然后就可以使用以下代码来调用存储过程,从远程服务器获取数据: ```sql DECLARE @result NVARCHAR(MAX); EXEC dbo.GetHttpData 'https://jsonplaceholder.typicode.com/todos/1', @result OUTPUT; SELECT @result; ``` 这将返回一个包含 JSON 数据的字符串。可以使用其他方法对返回的数据进行解析和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值