今下午没什么事,想将以前费了好大力气写的一个对二维表查询的存储过程进行改进,存储过程用到了好几个游标动态生成SQL,且有两三百行,不但别人很难看懂,自已隔一段时间去看,都得老半天。当初也时没办法,为了实现功能就没考虑这么多了,今就想试试用case when 能不能把游标给去了,使变得更简洁,可读性强,还可提高性能。

  做到一半时遇到一个问题,动态生成case when 拼装成的sql查询出的结果,按instanceID合并成一行的问题,将下图一的结果合并成图二的结果,

各列值的类型是不确定的(表中各列是用户通过系统自定义添加进去),要是数据型好办,用Sum函数。

C#实现SQL Server2005的扩展聚合函数 

                             图一 C#实现SQL Server2005的扩展聚合函数

 

 

 

 

 

 

                       图二

  想自定义一个类sum功能的对串进行拼接处理的聚合方法,在网上找了资料,发现可以用C#等语言开发自定义的聚合函数,因为.net是编译中 IL代码,理论上,只要是代码符合CTS,不同语言的代码是能互相调用。

     在vs2008用C#开发聚合函数过程:

 

首先用VS2008/VS2005建立一个SQL Server项目,如图6所示。

C#实现SQL Server2005的扩展聚合函数

图6

点击“确定”按钮后,SQL Server项目会要求连接一个数据库,我们可以选择一个数据库,如图7所示。

C#实现SQL Server2005的扩展聚合函数

图7

然后在工程中加入一个聚合类(joinstr.cs),如图8所示(可以开发Trigger 等)。

C#实现SQL Server2005的扩展聚合函数
C#实现SQL Server2005的扩展聚合函数

图8

joinstr.cs中的最终代码如下:

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


[Serializable]
[SqlUserDefinedAggregate(
    Format.UserDefined, 
//use custom serialization to serialize the intermediate result
    IsInvariantToNulls = true//optimizer property
    IsInvariantToDuplicates = false//optimizer property
    IsInvariantToOrder = false//optimizer property    
    MaxByteSize = 8000//maximum size in bytes of persisted value
]


public struct JionStr:IBinarySerialize
{
    
private StringBuilder sbIntermediate;
    
public void Init()
    {
       sbIntermediate 
= new StringBuilder();
    }

    
public void Accumulate(SqlString Value)
    {

        
if (Value == null || Value.ToString().ToLower().Equals("null"))
        {
            
return;
        }
        
else
        {
            sbIntermediate.Append(Value);
        }
    }

    
public void Merge(JionStr Group)
    {
        sbIntermediate.Append(Group.sbIntermediate);
    }

    
public SqlString Terminate()
    {
        
        
return new SqlString(sbIntermediate.ToString());
    }

    
// This is a place-holder member field
    private int var1;


    
#region IBinarySerialize Members

    
public void Read(System.IO.BinaryReader r)
    {
        sbIntermediate 
= new StringBuilder(r.ReadString());
    }

    
public void Write(System.IO.BinaryWriter w)
    {
        w.Write(
this.sbIntermediate.ToString());    
    }

    
#endregion
}

相关文章: