10

我有一个像这样的 SQL CLR 函数:

public partial class UserDefinedFunctions {
    [Microsoft.SqlServer.Server.SqlFunction(TableDefinition = "number int", FillRowMethodName = "FillRow")]
    public static IEnumerable MyClrFunction(object obj) {
        // read obj array input and then
        var result = new ArrayList();
        result.Add((SqlInt32)1);
        result.Add((SqlInt32)2);
        result.Add((SqlInt32)3);
        return result;
    }

    public static void FillRow(object obj, out SqlInt32 number) {
        number = (SqlInt32)obj;
    }

}

我想这样使用它:

DECLARE @x arrayOfInt

INSERT INTO @x VALUES (10)
INSERT INTO @x VALUES (20)
INSERT INTO @x VALUES (30)

SELECT * FROM dbo.MyClrFunction(@x)

arrayOfInt是:

CREATE TYPE [dbo].[arrayOfInt] AS TABLE(
[item] [int] NOT NULL,
PRIMARY KEY CLUSTERED 
    (
    [item] ASC
    ) WITH (IGNORE_DUP_KEY = OFF)
)

我遇到的问题是arrayOfInt与 sql_variant 不兼容。是否可以编写具有数组(表)参数的 CLR 表值函数?

4

1 回答 1

11

SQLCLR 不支持表值参数 (TVP):

  • 创建过程

    [ type_schema_name。] data_type
    ...
    CLR 过程指南:

    • 表值或游标数据类型不能用作参数。
  • 创建函数

    [ type_schema_name。] parameter_data_type ... 对于 CLR 函数,除了textntextimage、用户定义表类型和时间戳
    数据类型 之外,所有数据类型(包括 CLR 用户定义类型)都是允许的。

但是,您确实有几个选择:

  1. 如果数组是一个简单的数字和/或字符串列表,您始终可以发送一个带分隔符的值列表(通过 SqlString / NVARCHAR(MAX))并使用 String.Split() 对其进行解包。

  2. 如果数组更复杂(即多个字段),那么您可以将数据包装在 XML 中并将其作为 SqlXml 传递。

  3. 或者,如果您有一个复杂的数组,那么您可以创建一个 CLR UDT 作为您喜欢的任何结构并将其传递给函数。不过,这需要更多的努力。

  4. 另外,请记住,表值参数只是表(表变量),而不是内存中的数据结构,例如数组和集合。TVP 的主要好处和用例是在从应用程序向 SQL Server 发送数据时降低复杂性并提高性能。如果您已经在 SQL Server 内部,因此您正在创建一个表变量,然后想要将其传递给 CLR 存储过程(或者可能是函数),那么您需要做的就是以稍微不同的方式查看问题,然后您可以完成同样的基本事情:

    • 使用临时表而不是表变量
    • 将临时表名传递给 CLR 存储过程
    • 使用进程内连接(即连接字符串= "Context Connection = true;"),因为它可以访问本地临时对象
    • 您可以通过使用传入的表名在执行的任何 SQL 中使用临时表
    • 您可以通过对传入的表名执行一个简单的操作来将该表中的数据获取到 .NET 上下文SELECT *中,然后通过SqlCommand.ExecuteReader()和读取每一行SqlDataReader.Read()
于 2011-01-22T04:09:10.513 回答