转载——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.附录完整程序
- using System;
- using System.Data;
- using System.Data.SqlClient;
- using System.Data.SqlTypes;
- using Microsoft.SqlServer.Server;
- using System.Collections;
- using System.Collections.Generic;
- using System.Text;
- using System.Runtime.InteropServices;
- public partial class UserDefinedFunctions
- {
- #region Scalar
- /// <summary>
- /// 标量函数,不带参数
- /// </summary>
- /// <returns></returns>
- [Microsoft.SqlServer.Server.SqlFunction(
- DataAccess = DataAccessKind.Read)]
- 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);
- }
- }
- return returnValue;
- }
- /// <summary>
- /// 标量函数,带参数
- /// </summary>
- /// <param name="par"></param>
- /// <returns></returns>
- [Microsoft.SqlServer.Server.SqlFunction]
- public static SqlString UF_Scalar_SayHelloByPar(SqlString par)
- {
- return par;
- }
- #endregion
- #region Table
- /// <summary>
- /// 表值函数。
- /// </summary>
- /// <returns></returns>
- [Microsoft.SqlServer.Server.SqlFunction(
- DataAccess = DataAccessKind.Read,
- FillRowMethodName = "FillRow_ReturnData",
- IsDeterministic = true)]
- public static IEnumerable UF_Table_GetReturnData()
- {
- List<ReturnData> returnDataList = new List<ReturnData>();
- returnDataList.Add(new ReturnData("a", "a"));
- returnDataList.Add(new ReturnData("b", "b"));
- returnDataList.Add(new ReturnData("c", "c"));
- return returnDataList;
- }
- 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;
- }
- }
- 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;
- }
- }
- #endregion
- };
- #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;
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
转载——CLR标量函数、表值函数和聚合函数(UDA)的更多相关文章
- Spark SQL 用户自定义函数UDF、用户自定义聚合函数UDAF 教程(Java踩坑教学版)
在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...
- SQL语句函数详解__sql聚合函数
函数是一种有零个或多个参数并且有一个返回值的程序.在SQL中Oracle内建了一系列函数,这些函数都可被称为SQL或PL/SQL语句,函数主要分为两大类:单行函数.组函数 本文将讨论如何使用单行函数及 ...
- ORACLE字符串分组聚合函数(字符串连接聚合函数)
ORACLE字符串连接分组串聚函数 wmsys.wm_concat SQL代码: select grp, wmsys.wm_concat(str) grp, 'a1' str from dual un ...
- 【MySQL作业】avg 和 count 函数——美和易思聚合函数应用习题
点击打开所使用到的数据库>>> 1.统计所有商品的平均单价.最高单价与平均单价之差.平均单价与最低单价之差. 最高单价与平均单价之差 = max(unitPrice)-avg(uni ...
- 【MySQL作业】sum、max 和 min 聚合函数——美和易思聚合函数应用习题
点击打开所使用到的数据库>>> 1.统计商品最高单价和最低单价. -- 获取所有商品的最高单价和最低单价: select max(unitPrice) 最高单价 , min(unit ...
- SQL语言基本操作(聚合函数)
一.聚合函数 1.标量函数:只能对单个的数字或值进行计算.主要包括字符函数.日期/时间函数.数值函数和转换函数这四类.如LEFT/RIGHT/SUBSTRING/LTRIM/RTRIM/CONCAT/ ...
- sqlserver的over开窗函数(与排名函数或聚合函数一起使用)
首先初始化表和数据 create table t_student( Id INT, Name varchar(), Score int, ClassId INT ); insert i ...
- 10-31SQLserver基础--聚合函数、分组
在查询语句时,也存在一些方法和属性,而这些方法在查询时统称为函数,便利查询时使用 聚合函数(都是针对字段操作) 聚合是缩减一系列输入值的表达式,例如缩减为单个值. Select*from biao 1 ...
- MySQL数据库:聚合函数的使用
聚合函数 max() 最大值 min() 最小值 avg() 平均值 sum() 求和 count() 符合条件数据的数目 聚合函数不能嵌套使用 # 在统计时字段内没有满足条件的数值只有count返回 ...
随机推荐
- oracle sql语句中使用if逻辑
l在 SQL 语句中使用IF-THEN-ELSE 逻辑 l l使用两种方法: •CASE 表达式:SQL99的语法,类似Basic,比较繁琐 •DECODE 函数:Oracle自己的语法,类似Java ...
- C++拾遗(六)函数相关(1)
返回值 C++规定返回值不能是 数组.但可以是其它任何类型(包括结构体和对象). 通常,函数将返回值复制到指定的CPU寄存器或内存单元中,然后调用函数调用该内存单元的值. 函数原型 参数列表中可以不包 ...
- 【转载】经典10道c/c++语言经典笔试题(含全部所有参考答案)
经典10道c/c++语言经典笔试题(含全部所有参考答案) 1. 下面这段代码的输出是多少(在32位机上). char *p; char *q[20]; char *m[20][20]; int (*n ...
- 网易JS面试题与Javascript词法作用域说明
调用对象位于作用域链的前端,局部变量(在函数内部用var声明的变量).函数参数及Arguments对象都在函数内的作用域中--这意味着它们隐藏了作用域链更上层的任何同名的属性. 2010年9月14日, ...
- 使用微软 AppFabric 遇到问题
我做的一个项目用了,但是遇到很奇怪的问题,在测试环境下,两台机做集群,一切正常,达到设计要求,但是部署到专用网络(内部网络,无法访问internet),老是提示访问服务器超时,初步排查,发现貌似是域的 ...
- ECSTORE2.0 去页面底部版权
ECstore系统在每个页面底部都有版权信息,非常烦人,之前的解决方法是修改系统代码,但是对不懂的php代码人来说是个很困扰的事情. 现在ECStore在版本为2.0.32中进行了代码更新,只需要在c ...
- phpcms v9 数据库分离部署
v9数据模型功能,允许用户把不同的数据表,分离到不同的数据库服务器上.以实现负载的分离,更加的符合大访问网站的需求. <ignore_js_op> 数据分离方法 1.数据库连接配置配置文件 ...
- nginx配置使其支持thinkphp的pathinfo模式
#user root;#user nobody;worker_processes 1; #error_log logs/error.log;#error_log logs/error.log noti ...
- centos6.2下安装星际译王stardict3.0
星际译王是一个Linux下很好的翻译软件. 我的系统是centos6.2 32位版.本来在http://code.google.com/p/stardict-3/downloads/list 上下的源 ...
- 猜数字-js
var n = Math.round(Math.random()*10); //随机数 // alert(n); while(true){ var Onum = prompt('请输入1-10之间的数 ...