• 全部
...

【交流】SQL2005CLR函数扩展-环比计算

jinjazz 2009-04-28 11:54:51
加精
blog原文,希望大家支持我的blog
http://blog.csdn.net/jinjazz/archive/2009/04/28/4132162.aspx

---------

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

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

clr的代码如下,编译为TestFun.dll,复制到sql服务器的文件目录下
  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4. using System.Data.SqlTypes;
  5. using Microsoft.SqlServer.Server;

  6. public partial class UserDefinedFunctions
  7. {

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

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


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

  26. //组变更
  27. if (_listGroup[key.Value] != currentGroup.Value)
  28. {
  29. prevMemberValue = SqlString.Null;
  30. _listGroup[key.Value] = currentGroup.Value;
  31. }
  32. //值变更
  33. _listValue[key.Value] = currentValue;

  34. return prevMemberValue;
  35. }
  36. catch
  37. {
  38. return SqlString.Null;
  39. }
  40. }
  41. /// <summary>
  42. /// 初始化并发键
  43. /// </summary>
  44. /// <param name="key"></param>
  45. /// <returns></returns>
  46. [Microsoft.SqlServer.Server.SqlFunction]
  47. public static SqlBoolean InitKey(SqlString key)
  48. {
  49. try
  50. {
  51. _listValue.Add(key.Value, SqlString.Null);
  52. _listGroup.Add(key.Value, string.Empty);
  53. return true;
  54. }
  55. catch
  56. {
  57. return false;
  58. }
  59. }
  60. /// <summary>
  61. /// 释放并发键
  62. /// </summary>
  63. /// <param name="key"></param>
  64. /// <returns></returns>
  65. [Microsoft.SqlServer.Server.SqlFunction]
  66. public static SqlBoolean DisposeKey(SqlString key)
  67. {
  68. try
  69. {
  70. _listValue.Remove(key.Value);
  71. _listGroup.Remove(key.Value);
  72. return true;
  73. }
  74. catch
  75. {
  76. return false;
  77. }
  78. }
  79. };


部署和生成自定义函数,其中考虑到并发,我们还是需要一个并发键来表达当前查询
  1. CREATE ASSEMBLY TestForSQLCLR FROM 'E:\sqlclrdata\TestFun.dll' WITH PERMISSION_SET = UnSAFE;
  2. --
  3. go
  4. --获取上个维度
  5. CREATE FUNCTION dbo.xfn_GetPrevMemberValue
  6. (
  7. @key nvarchar(255),
  8. @initByDim nvarchar(255),
  9. @currentValue nvarchar(255)
  10. )
  11. RETURNS nvarchar(255)
  12. AS EXTERNAL NAME TestForSQLCLR.[UserDefinedFunctions].GetPrevMemberValue
  13. go

  14. --初始化并发键
  15. CREATE FUNCTION dbo.xfn_initKey
  16. (
  17. @key nvarchar(255)
  18. )
  19. RETURNS bit
  20. AS EXTERNAL NAME TestForSQLCLR.[UserDefinedFunctions].InitKey
  21. go
  22. --清理并发键
  23. CREATE FUNCTION dbo.xfn_disposeKey
  24. (
  25. @key nvarchar(255)
  26. )
  27. RETURNS bit
  28. AS EXTERNAL NAME TestForSQLCLR.[UserDefinedFunctions].DisposeKey


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

  1. --建立测试环境
  2. declare @t table(
  3. [区域] [varchar](4) COLLATE Chinese_PRC_CI_AS NULL,
  4. [TradeMonth] [varchar](7) COLLATE Chinese_PRC_CI_AS NULL,
  5. [TradeMoney] [float] NULL,
  6. [TradeArea] [float] NULL,
  7. [TradePrice] [float] NULL
  8. )
  9. insert into @t
  10. select '闵行','2007-03','2125714.91','241.65','8796.67' union
  11. select '闵行','2007-04','8408307.64','907.32','9267.19' union
  12. select '闵行','2007-05','10230321.95','1095.88','9335.26' union
  13. select '浦东','2007-01','12738432.25','1419.05','8976.73' union
  14. select '浦东','2007-02','4970536.74','395.49','12568.05' union
  15. select '浦东','2007-03','5985405.76','745.94','8023.98' union
  16. select '浦东','2007-04','21030788.61','1146.89','18337.23' union
  17. select '普陀','2007-01','1863896','161.39','11549.02' union
  18. select '普陀','2007-02','1614015','119.59','13496.24' union
  19. select '普陀','2007-03','1059235.19','135.21','7834'

  20. --测试语句
  21. declare @key varchar(40)
  22. declare @b bit

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

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


  30. --结果
  31. /*

  32. 区域 TradeMonth TradePrice LastMonthPrice 环比
  33. ---- ---------- ---------------------- ---------------------- -----------
  34. 闵行 2007-03 8796.67 NULL NULL
  35. 闵行 2007-04 9267.19 8796.67 5.35%
  36. 闵行 2007-05 9335.26 9267.19 0.73%
  37. 浦东 2007-01 8976.73 NULL NULL
  38. 浦东 2007-02 12568.05 8976.73 40.01%
  39. 浦东 2007-03 8023.98 12568 -36.16%
  40. 浦东 2007-04 18337.23 8023.98 128.53%
  41. 普陀 2007-01 11549.02 NULL NULL
  42. 普陀 2007-02 13496.24 11549 16.86%
  43. 普陀 2007-03 7834 13496.2 -41.95%

  44. */


这个函数写的还是比较粗糙,如果进一步改进还可以详细定义如何获取上一个维度的方法。这里只是根据查询顺序来做缓存。感兴趣的朋友可以完善一下。
...全文
给本帖投票
641 25 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
lubingll 2010-04-11
  • 打赏
  • 举报
回复
看不懂,先收藏,后学习
coolfsa896 2009-05-02
  • 打赏
  • 举报
回复
学习一下~~
tjwater20 2009-04-30
  • 打赏
  • 举报
回复
haoahoahoahoahao
a285232083 2009-04-29
  • 打赏
  • 举报
回复
Arial2010 2009-04-29
  • 打赏
  • 举报
回复
现在还看不懂啊郁闷
jinjazz 2009-04-29
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 octverve 的回复:]
按楼主这样弄,环比,同比就没有太多价值了~
[/Quote]

价值不是实现方式决定的,是需求决定的。
SlaughtChen 2009-04-29
  • 打赏
  • 举报
回复
mark
octverve 2009-04-29
  • 打赏
  • 举报
回复
按楼主这样弄,环比,同比就没有太多价值了~
dinzjiaoyu 2009-04-28
  • 打赏
  • 举报
回复
长沙鼎卓人力资源管理公司教育部为社会下岗失业人员、转业军人、应、往届大学毕业生,为想学一技之长的青年免费提供电工、焊工培训,报名地址:五一广场平和堂对面锦绣中环28楼、联系电话:0731-4440515,联系人:赵老师
xiaomeixiang 2009-04-28
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 liangCK 的回复:]
学习.
[/Quote]
liangCK 2009-04-28
  • 打赏
  • 举报
回复
学习.
fcuandy 2009-04-28
  • 打赏
  • 举报
回复
..
  • 打赏
  • 举报
回复
学学习
qqhmitzk 2009-04-28
  • 打赏
  • 举报
回复
学习
水族杰纶 2009-04-28
  • 打赏
  • 举报
回复
頂下~~
jinjazz 2009-04-28
  • 打赏
  • 举报
回复
自己mark一下,吃饭去
-狙击手- 2009-04-28
  • 打赏
  • 举报
回复
..
angelalien 2009-04-28
  • 打赏
  • 举报
回复
还没有用过.不知道怎样
lsd123 2009-04-28
  • 打赏
  • 举报
回复
.
laozihuen520 2009-04-28
  • 打赏
  • 举报
回复
dfgfd gfd gdf gd gddfgdg
加载更多回复(5)

34,838

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧

手机看
关注公众号

关注公众号

客服 返回
顶部