转载——CLR标量函数、表值函数和聚合函数(UDA)

本节主要介绍使用CLR创建标量函数,表值函数和聚合函数。

所谓标量函数指的就是此函数只返回一个值。表值函数返回值是一个表。聚合函数是在select语句中使用的,用来聚合一个结果集,类似于Sum()或是Count()等内置的函数,而且真正的自定义聚合函数目前只能用CLR来实现。

下面的例子使用了SQLServer自带的pubs数据库。

1.CLR标量函数

1.1无参函数 
    /// 
    /// 标量函数,不带参数 
    /// 
    /// 
    [Microsoft.SqlServer.Server.SqlFunction( 
        DataAccess = DataAccessKind.Read, 
        IsDeterministic = true)] 
    public static SqlString UF_Scalar_SayHello() 
    { 
        string returnValue = "null"; 
        //由于程序是在SQL Server内执行,所以连接字符串写成"context connection=true"即可 
        using (SqlConnection conn = new SqlConnection("context connection=true")) 
        { 
            conn.Open(); 
            SqlCommand com = new SqlCommand("select top 1 [au_lname] from [dbo].[authors]",conn); 
            using (SqlDataReader dr = com.ExecuteReader(CommandBehavior.CloseConnection)) 
            { 
                if (dr.Read()) 
                    returnValue = dr.GetString(0);//返回au_lname 
            } 
        }

return returnValue;//返回"null” 
    }

CLR函数用Microsoft.SqlServer.Server.SqlFunction特征进行修饰。里面的参数含义为:DataAccess = DataAccessKind.Read表示可访问数据表。关于SqlFunctionAttribute的属性将附录在文章的最后。

/// 
    /// 标量函数,带参数 
    /// 
    /// 
    /// 
    [Microsoft.SqlServer.Server.SqlFunction] 
    public static SqlString UF_Scalar_SayHelloByPar(SqlString par) 
    { 
        return par; 
    }

2.CLR表值函数

表值与标量函数有些不同。因为要返回一个数据集合,所以一定要用一个填充数据的方法,在属性中用FillRowMethodName来表示,且返回值应该为IEnumerable类型。代码如下:

1.首先自定义返回类型 
public class ReturnData 
    { 
        public SqlString Name { get; set; } 
        public SqlString Password { get; set; } 
        public ReturnData(string name, string password) 
        { 
            this.Name = name; 
            this.Password = password; 
        } 
    }

2.写CLR表值函数 
[Microsoft.SqlServer.Server.SqlFunction( 
        DataAccess = DataAccessKind.Read, 
        FillRowMethodName = "FillRow_ReturnData",//这里是此函数的具体填充方法 
        IsDeterministic = true)] 
    public static IEnumerable UF_Table_GetReturnData() 
    { 
        List returnDataList = new List(); 
        returnDataList.Add(new ReturnData("a", "a")); 
        returnDataList.Add(new ReturnData("b", "b")); 
        returnDataList.Add(new ReturnData("c", "c")); 
        return returnDataList; 
    }

3.写填充方法 
public static void FillRow_ReturnData(object returnDataObj, 
                       out SqlString name, 
                       out SqlString password) 
    { 
        ReturnData item = returnDataObj as ReturnData; 
        name = ""; 
        password = ""; 
        if (item != null) 
        { 
            name = item.Name; 
            password = item.Password; 
        } 
    }

这样一个表值函数就写好了。确定有点麻烦,但是表值在某种情况下,也是不可替代的。

3.CLR聚合函数

用户自定义的CLR聚合类中必须四个函数:Init,Accumulate,Merge,Terminate。Init用户初始化,Accumulate用来实现具体的聚合算法,Merge用来执行每一次的聚合逻辑顺序,Terminate用来将聚合的结果返回。 
下面的代码显示了字符串的自定义聚合

#region Aggregation 
[Serializable] 
[StructLayout(LayoutKind.Sequential)] 
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate( 
    Format.UserDefined, 
    IsInvariantToDuplicates = false, 
    IsInvariantToNulls = true, 
    IsInvariantToOrder = false, 
    MaxByteSize=8000)] 
public class StringAgg : IBinarySerialize 

    private StringBuilder strBuffer;

public void Init() 
    { 
        strBuffer = new StringBuilder(); 
    }

public void Accumulate(SqlString str) 
    { 
        strBuffer.Append(string.Format("{0},", str)); 
    }

public void Merge(StringAgg Group) 
    { 
        Accumulate(Group.Terminate()); 
    }

public SqlString Terminate() 
    { 
        return strBuffer.ToString(); 
    }

#region IBinarySerialize Members

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

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

#endregion 

#endregion;

4.创建函数的SQL脚本及调用方法 
关于CLR Assembly的创建方法前面已经讲过了,这里不再重复 
--创建函数 
create function UF_Scalar_SayHello() 
returns nvarchar(32) 
as EXTERNAL NAME CLRDemoAssemly.UserDefinedFunctions.UF_Scalar_SayHello 
go 
create function UF_Scalar_SayHelloByPar(@Par nvarchar(32)) 
returns nvarchar(32) 
as EXTERNAL NAME CLRDemoAssemly.UserDefinedFunctions.UF_Scalar_SayHelloByPar 
go 
create function UF_Table_GetReturnData() 
returns table(Name nvarchar(32),Password nvarchar(32)) 
as EXTERNAL NAME CLRDemoAssemly.UserDefinedFunctions.UF_Table_GetReturnData 
go 
create AGGREGATE StringAgg(@Par nvarchar(32)) 
returns nvarchar(max) 
EXTERNAL NAME CLRDemoAssemly.StringAgg 
go 
select dbo.UF_Scalar_SayHello() 
go 
select dbo.UF_Scalar_SayHelloByPar(‘Hello TJVictor‘) 
go 
select * from dbo.UF_Table_GetReturnData() 
go 
select dbo.StringAgg(au_lname) from dbo.authors

5.SqlFunctionAttribute的属性 

名称 说明
DataAccess 指示函数是否需要访问存储在 SQL Server 的本地实例中的用户数据。
FillRowMethodName 方法的名称,该方法与 TVF 协定所使用的表值函数 (TVF) 在同一个类中。
IsDeterministic 指示用户定义的函数是否是确定性的。
IsPrecise 指示函数是否涉及不精确的计算,如浮点运算。
Name 函数在 SQL Server 中注册时所使用的名称。
SystemDataAccess 指示函数是否需要访问存储在 SQL Server 的系统目录或虚拟系统表中的数据。
TableDefinition 如果方法用作表值函数 (TVF),则为一个字符串,该字符串表示结果的表定义。
TypeId 当在派生类中实现时,获取该 Attribute 的唯一标识符。

6.SqlUserDefinedAggregateAttribute的属性

名称 说明
Format 序列化格式为 Format 的值之一。如果选择Native,则聚合类一定要被[StructLayout(LayoutKind.Sequential)]修饰;如果选择UserDefined,则聚合类一定要继承IBinarySerialize接口,自己写序列化方法。
IsInvariantToDuplicates 指示聚合是否与重复值无关。
IsInvariantToNulls 指示聚合是否与空值无关。
IsInvariantToOrder 指示聚合是否与顺序无关。
IsNullIfEmpty 指示在没有对任何值进行累积时聚合是否返回空引用。
MaxByteSize 聚合实例的最大大小。
Name 聚合的名称。
TypeId 当在派生类中实现时,获取该 Attribute 的唯一标识符。

7.附录完整程序

[c-sharp] view plaincopy

  1. using System;
  2. using System.Data;
  3. using System.Data.SqlClient;
  4. using System.Data.SqlTypes;
  5. using Microsoft.SqlServer.Server;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Text;
  9. using System.Runtime.InteropServices;
  10. public partial class UserDefinedFunctions
  11. {
  12. #region Scalar
  13. /// <summary>
  14. /// 标量函数,不带参数
  15. /// </summary>
  16. /// <returns></returns>
  17. [Microsoft.SqlServer.Server.SqlFunction(
  18. DataAccess = DataAccessKind.Read)]
  19. public static SqlString UF_Scalar_SayHello()
  20. {
  21. string returnValue = "null";
  22. //由于程序是在SQL Server内执行,所以连接字符串写成"context connection=true"即可
  23. using (SqlConnection conn = new SqlConnection("context connection=true"))
  24. {
  25. conn.Open();
  26. SqlCommand com = new SqlCommand("select top 1 [au_lname] from [dbo].[authors]", conn);
  27. using (SqlDataReader dr = com.ExecuteReader(CommandBehavior.CloseConnection))
  28. {
  29. if (dr.Read())
  30. returnValue = dr.GetString(0);
  31. }
  32. }
  33. return returnValue;
  34. }
  35. /// <summary>
  36. /// 标量函数,带参数
  37. /// </summary>
  38. /// <param name="par"></param>
  39. /// <returns></returns>
  40. [Microsoft.SqlServer.Server.SqlFunction]
  41. public static SqlString UF_Scalar_SayHelloByPar(SqlString par)
  42. {
  43. return par;
  44. }
  45. #endregion
  46. #region Table
  47. /// <summary>
  48. /// 表值函数。
  49. /// </summary>
  50. /// <returns></returns>
  51. [Microsoft.SqlServer.Server.SqlFunction(
  52. DataAccess = DataAccessKind.Read,
  53. FillRowMethodName = "FillRow_ReturnData",
  54. IsDeterministic = true)]
  55. public static IEnumerable UF_Table_GetReturnData()
  56. {
  57. List<ReturnData> returnDataList = new List<ReturnData>();
  58. returnDataList.Add(new ReturnData("a", "a"));
  59. returnDataList.Add(new ReturnData("b", "b"));
  60. returnDataList.Add(new ReturnData("c", "c"));
  61. return returnDataList;
  62. }
  63. public class ReturnData
  64. {
  65. public SqlString Name { get; set; }
  66. public SqlString Password { get; set; }
  67. public ReturnData(string name, string password)
  68. {
  69. this.Name = name;
  70. this.Password = password;
  71. }
  72. }
  73. public static void FillRow_ReturnData(object returnDataObj,
  74. out SqlString name,
  75. out SqlString password)
  76. {
  77. ReturnData item = returnDataObj as ReturnData;
  78. name = "";
  79. password = "";
  80. if (item != null)
  81. {
  82. name = item.Name;
  83. password = item.Password;
  84. }
  85. }
  86. #endregion
  87. };
  88. #region Aggregation
  89. [Serializable]
  90. [StructLayout(LayoutKind.Sequential)]
  91. [Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
  92. Format.UserDefined,
  93. IsInvariantToDuplicates = false,
  94. IsInvariantToNulls = true,
  95. IsInvariantToOrder = false,
  96. MaxByteSize=8000)]
  97. public class StringAgg : IBinarySerialize
  98. {
  99. private StringBuilder strBuffer;
  100. public void Init()
  101. {
  102. strBuffer = new StringBuilder();
  103. }
  104. public void Accumulate(SqlString str)
  105. {
  106. strBuffer.Append(string.Format("{0},", str));
  107. }
  108. public void Merge(StringAgg Group)
  109. {
  110. Accumulate(Group.Terminate());
  111. }
  112. public SqlString Terminate()
  113. {
  114. return strBuffer.ToString();
  115. }
  116. #region IBinarySerialize Members
  117. public void Read(System.IO.BinaryReader r)
  118. {
  119. strBuffer = new StringBuilder(r.ReadString());
  120. }
  121. public void Write(System.IO.BinaryWriter w)
  122. {
  123. w.Write(strBuffer.ToString());
  124. }
  125. #endregion
  126. }
  127. #endregion;

CLR系列文章链接:
SQL Server CLR全功略之一---CLR介绍和配置:
http://blog.csdn.net/tjvictor/archive/2009/10/25/4726933.aspx

SQL Server CLR全功略之二---CLR存储过程:
http://blog.csdn.net/tjvictor/archive/2009/10/26/4731052.aspx

SQL Server CLR全功略之三---CLR标量函数、表值函数和聚合函数(UDA):
http://blog.csdn.net/tjvictor/archive/2009/11/10/4793781.aspx

SQL Server CLR全功略之四---CLR触发器:
http://blog.csdn.net/tjvictor/archive/2009/11/10/4795569.aspx

SQL Server CLR全功略之五---CLR自定义数据类型

http://blog.csdn.net/tjvictor/archive/2009/11/13/4807901.aspx

如需转载,请注明本文原创自CSDN TJVictor专栏:http://blog.csdn.net/tjvictor

时间: 2024-07-31 14:25:55

转载——CLR标量函数、表值函数和聚合函数(UDA)的相关文章

MySQL学习19:运算符与函数之信息函数、聚合函数、加密函数

信息函数 常用的信息函数有: (1)查看数据库连接ID和当前数据库 SELECT CONNECTION_ID(); SELECT DATABASE(); (2)查看最后输入记录的ID号 ALTER TABLE test ADD id SMALLINT UNSIGNED KEYAUTO_INCREMENT  FIRST; INSERT test(first_name,last_name) VALUES('11','22'); SELECT LAST_INSERT_ID(); SELECT * FR

oracle中的聚合函数count、max、min、sum、avg以及NVL函数的用法

oracle中的聚合函数count.max.min.sum.avg以及NVL函数的用法 分组函数聚合函数对一组行中的某个列执行计算执行计算并返回单一的值.聚合函数忽略空值.聚合函数经常与 SELECT 语句的 GROUP BY 子句一同使用,所以有的时候也把其称之为分组函数.这类函数通常应用于报表统计中,以下展示Oracle常用的聚合函数的应用. 分组函数的介绍 作用于一组数据,并对一组数据返回一个值. 常见的分组函数有: Count 用来计算有效数据的数量 Min 返回一个数字列或计算列的最小

SSRS 2012 聚合函数 -- 介绍

SSRS 2012 聚合函数 -- 介绍 数据的运算除了单笔计算之外,同时还需要进行汇总计算,因此,SSRS中提供了一些列的聚合函数,凡是熟悉的加和.平均.计数.分组计数.最大值.最小值都有函数可以使用. 常用聚合函数 函数 说明 Avg 返回指定表达式的所有非Null平均值 Count 从指定表达式返回值的计数 CountDistinct 从指定表达式返回所有分组值的计数 CountRows 返回指定范围内的数据行计数 First 从指定表达式返回第一个值 Last 从指定表达式返回最后一个值

10-31C#基础--数据库查询语句之聚合函数、分组

在查询语句时,也存在一些方法和属性,而这些方法在查询时统称为函数,便利查询时使用 聚合函数(都是针对字段操作) 聚合是缩减一系列输入值的表达式,例如缩减为单个值. Select*from biao 1.--求平均分AVG:只能对数字类型的操作,返回一个值(返回非null值的平均值) Select AVG(age)from biao--执行后没有列名 Select AVG(age) as nianing from biao---执行后有列名,加as. --放在select...from之间的一定是

sqlserver的over开窗函数(与排名函数或聚合函数一起使用)

首先初始化表和数据 1 create table t_student( 2   Id INT, 3   Name varchar(100), 4   Score int, 5   ClassId INT 6 ); 7 8 insert into t_student values (1,'A',75,1); 9 insert into t_student values (2,'B',78,2); 10 insert into t_student values (3,'C',74,1); 11 in

oracle中的常用函数、字符串函数、数值类型函数、日期函数,聚合函数。

一.字符串的常用函数. --一.oracle 字符串常用函数 --1. concat 连接字符串的函数,只能连接[两个]字符串. 字符写在括号中,并用逗号隔开! --2.“||”符号可以连接多个字符串 直接用||将多个字符链接即可. --3. dual? dual是一个虚拟表,用来构成select的语法规则,oracle保证dual里面永远只有一条记录. select concat('lo','ve')from dual; select concat('o','k')from dual; sel

MySQL数据库:聚合函数的使用

聚合函数 max() 最大值 min() 最小值 avg() 平均值 sum() 求和 count() 符合条件数据的数目 聚合函数不能嵌套使用 # 在统计时字段内没有满足条件的数值只有count返回数值0或者其他,而其余四个聚合函数返回null; # 对于聚合函数的参数,很多时候使用字段名来表示,那么这个时候,该字段内的null值不参与统计 count(*) 显示表中符合条件的信息数目,不考虑某字段出现null值 select count(cID),avg(elScore) from elog

【SQL】CLR聚合函数什么鬼

之前写过一个合并字符串的CLR聚合函数,基本是照抄MS的示例,外加了一些处理,已经投入使用很长时间,没什么问题也就没怎么研究,近日想改造一下,遇到一些问题,遂捣鼓一番,有些心得,记录如下. 一.杂项 CLR聚合函数在SQL中虽然是函数,但在C#中实际上是以一个类或结构的形式存在的(是的,实现聚合函数的实体可以是结构,也可以是类),这点有别于CLR普通函数,后者是类中的一个方法,鉴于此,下文把实现聚合函数的类或结构统称为聚合类,以免读者思维混淆 聚合类必须用特性[SqlUserDefinedAgg

SQL Server 自定义聚合函数

说明:本文依据网络转载整理而成,因为时间关系,其中原理暂时并未深入研究,只是整理备份留个记录而已. 目标:在SQL Server中自定义聚合函数,在Group BY语句中 ,不是单纯的SUM和MAX等运算,可以加入拼接字符串. 环境: 1:Sqlserver 2008 R2 2:Visual Studio 2013 第一部分: .net代码: using System; using System.Data; using Microsoft.SqlServer.Server; using Syst