10

我们有一个第三方 DLL,它可以对源信息的 DataTable 进行操作并生成一些有用的值,我们正在尝试通过 SQLCLR 将其连接起来,以便在 SQL Server 2008 中作为表值 UDF 进行调用。

将这里的概念更进一步,我想编写一个CLR 表值函数,该函数对来自数据库的源数据表进行操作。

我很确定我了解在 T-SQL 方面需要发生什么;但是,.NET (C#) 代码中的方法签名应该是什么样子?“来自 SQL Server 的表数据”的参数数据类型是什么?

例如

/* Setup */
CREATE TYPE InTableType 
AS TABLE (LocationName VARCHAR(50), Lat FLOAT, Lon FLOAT)
GO 

CREATE TYPE OutTableType 
AS TABLE (LocationName VARCHAR(50), NeighborName VARCHAR(50), Distance FLOAT)
GO

CREATE ASSEMBLY myCLRAssembly 
FROM 'D:\assemblies\myCLR_UDFs.dll' 
WITH PERMISSION_SET = EXTERNAL_ACCESS
GO
CREATE FUNCTION GetDistances(@locations InTableType)
RETURNS OutTableType
AS 
EXTERNAL NAME myCLRAssembly.GeoDistance.SQLCLRInitMethod
GO

/* Execution */

DECLARE @myTable InTableType
INSERT INTO @myTable(LocationName, Lat, Lon) VALUES('aaa', -50.0, -20.0)
INSERT INTO @myTable(LocationName, Lat, Lon) VALUES('bbb', -20.0, -50.0)
SELECT * FROM @myTable

DECLARE @myResult OutTableType
INSERT INTO @myResult
GetDistances @myTable /* SQLCLR Call: GeoDistance.SQLCLRInitMethod(@myTable) */

lat/lon -> distance 是一个愚蠢的例子,当然应该更好地完全在 SQL 中处理;但我希望它通过绑定到 SQLCLR 程序集的表值 UDF 来说明 table-in -> table-out 的一般意图。

我不确定这是否可能;SQLCLRInitMethod 方法签名在 C# 中会是什么样子?

public class GeoDistance
{
    [SqlFunction(FillRowMethodName = "FillRow")]
    public static IEnumerable SQLCLRInitMethod(<appropriateType> myInputData)
    {
      //...
    }

    public static void FillRow(...)
    {
      //...
    }
}

如果不可能,我知道我可以在 C# 代码中使用“context connection=true”SQL 连接,让 CLR 组件在给定相关键的情况下查询必要的数据;但这对数据库模式的变化很敏感。所以我希望让 SQL 捆绑所有源数据并将其传递给函数。

额外的问题 - 假设这完全有效,它是否也适用于多个输入表?

4

2 回答 2

9

事实证明,SQLCLR 函数上有一个固定的有效输入列表,由.NET 数据类型和 SQL 数据类型之间的可用映射决定

SQL 数据类型“表”被显式调用为没有通过 CLR 的映射。

因此,不可能将表值数据作为方法参数传递到表值 CLR 函数中。

备择方案

似乎可以通过select ... for xml扭曲获取表格数据以输入SqlXml参数。

我已经成功地SqlConnection conn = new SqlConnection("context connection = true");在 .NET 代码中使用,让 TVF 查询数据库以获取它需要的表格数据。

于 2010-06-17T00:50:28.063 回答
3

这个问题似乎(主要)是重复的:

带数组参数的 CLR 表值函数

快速说明一下,在那个问题中,我推荐:分隔列表、XML 或 CLR UDT。

还可以选择在函数中填充表格并从中加载 DataTable。可能不建议使用真正的表,因为它需要额外的努力才能使其“线程安全”(不与其他 SPID 交叉数据),并且需要额外的清理过程,因为函数将无法执行 DML声明以在处理完数据后对其进行清理。在某些情况下,这可能是首选,但可能不适用于这种特殊情况。幸运的是,临时在 SQLCLR 函数中可访问(作为只读,但在 T-SQL 函数中根本无法访问)。使用临时表与使用永久表具有相同的优点,但没有与其他 SPID 冲突或需要单独清理的缺点。唯一的要求是您使用上下文连接,因为这是访问基于会话的对象(即临时表)的唯一方法。

因此,对于这种特殊情况,我建议尝试使用 Temp Table 或 XML 选项。

于 2011-01-22T04:42:27.447 回答