演练:调试 SQL CLR 用户定义的聚合
更新:2007 年 11 月
本主题适用于:
版本 |
Visual Basic |
C# |
C++ |
Web Developer |
---|---|---|---|---|
速成版 |
||||
标准版 |
||||
专业团队版 |
表格图例:
适用 |
|
不适用 |
|
默认情况下隐藏的一条或多条命令。 |
此示例显示如何调试 CLR SQL 用户定义的聚合。它在“AdventureWorks”示例数据库中创建一个新的名为“Concatenate”的 CLR SQL 聚合函数。当在 SQL 语句中调用此函数时,它将作为其输入参数的指定的列的所有值串联在一起。
说明: |
---|
显示的对话框和菜单命令可能会与“帮助”中的描述不同,具体取决于您的当前设置或版本。若要更改设置,请在“工具”菜单上选择“导入和导出设置”。有关更多信息,请参见 Visual Studio 设置。 |
调试 CLR SQL 聚合函数
在一个新的 SQL Server 项目中,建立一个到“AdventureWorks”示例数据库的连接。有关更多信息,请参见 如何:连接到数据库。
使用以下示例部分中第一个示例的代码创建一个新的函数,并将其命名为“Concatenate.cs”。有关更多信息,请参见 如何:使用 SQL Server 项目类型进行开发。
添加一个对该功能进行测试的脚本,方法是,在 SELECT 语句中包括该脚本。在“解决方案资源管理器”中右击“TestScripts”目录,选择“添加测试脚本”,然后插入本演练中第二个示例部分的代码。以“Concatenate.sql”名称保存文件。右击该文件名,然后单击“设置为默认调试脚本”。
将断点放置在 Concatenate.cs 中的 Accumulate 方法内的 if 语句上。若要执行此操作,请单击“文本编辑器”窗口左侧的灰色空白处,然后在“调试”菜单上单击“启动”,以对项目执行编译、部署和单元测试。以黄色箭头表示的指令指针出现在断点上时,说明正在调试函数。
尝试各种调试功能。
对于 Concatenate.sql 中构成脚本的 GROUP BY 子句的每一行,都会执行一次 Accumulate 方法。通过在“调试”菜单上重复单击“逐语句”,可监视方法结果的生成方式。
在“局部变量”窗口中,打开变量 value,它包含当前正处理的存储区名称。
单击变量 this。此函数将返回子节点 intermediateResult,该节点包含到当前存储名为止的所有存储名,这些存储名连接在一起并以逗号分隔。
在文本编辑器中,双击 intermediateResult 变量以选择它。将 intermediateResult 拖动到“监视”窗口,并将它放在窗口中的任意位置。该变量随即添加到受监视的变量列表中。
逐句通过方法几次。每次通过该方法时,intermediateResult 的值都将更改,并在结尾处连接另外一个存储名。
单击断点以将其移除,然后向 Terminate 方法内的第一个语句添加断点。此方法将结果返回给调用方。若要单步执行它,请在“调试”菜单上单击“启动”。现在可以通过单击“调试”菜单上的“单步执行”来逐句通过它。在遇到 return 语句时停止。
再次单击“继续”完成函数调试。
示例
下面是本示例中使用的聚合函数的代码。
using System;
using System.Data.Sql;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.Text;
[Serializable]
[SqlUserDefinedAggregate(
//use CLR serialization to serialize the intermediate result.
Format.UserDefined,
//Optimizer property:
IsInvariantToNulls=true,
//Optimizer property:
IsInvariantToDuplicates=false,
//Optimizer property:
IsInvariantToOrder=false,
//Maximum size in bytes of persisted value:
MaxByteSize=8000)
]
public class Concatenate: IBinarySerialize
{
/// <summary>
/// Variable holds intermediate result of the concatenation
/// </summary>
private StringBuilder intermediateResult;
/// <summary>
/// Initialize the internal data structures
/// </summary>
public void Init( )
{
intermediateResult = new StringBuilder();
}
/// <summary>
/// Accumulate the next value, nop if the value is null
/// </summary>
/// <param name="value"></param>
public void Accumulate(SqlString value)
{
if(value.IsNull)
{
return;
}
intermediateResult.Append(value.Value).Append(',');
}
/// <summary>
/// Merge the partially computed aggregate with this aggregate.
/// </summary>
/// <param name="other"></param>
public void Merge( Concatenate other)
{
intermediateResult.Append(other.intermediateResult);
}
/// <summary>
/// Called at end of aggregation, to return results.
/// </summary>
/// <returns></returns>
public SqlString Terminate()
{
string output = string.Empty;
//Delete the trailing comma, if any .
if (intermediateResult != null && intermediateResult.Length > 0)
output = intermediateResult.ToString(0, intermediateResult.Length-1);
return new SqlString(output);
}
public void Read(BinaryReader r)
{
intermediateResult = new StringBuilder(r.ReadString());
}
public void Write(BinaryWriter w)
{
w.Write(intermediateResult.ToString());
}
}
这是调用此函数的测试脚本。
SELECT scu.SalesPersonID, dbo.Concatenate(sst.Name)
FROM Sales.Customer as scu
INNER JOIN Sales.Store as sst
ON scu.CustomerID = sst.CustomerID
INNER JOIN Sales.SalesPerson as spr
ON scu.SalesPersonID = spr.SalesPersonID
WHERE scu.SalesPersonID = 283
GROUP BY scu.SalesPersonID