SQLCLR .NET Error: Object reference not set to an instance of an object

SQLCLR .NET Error: Object reference not set to an instance of an object

我目前在尝试执行一个简单的 SELECT 语句时收到一个错误,该语句引用了一个包含 Jaro-Winkler 距离算法的 C# 代码的程序集。这是我第一次使用 SQLCLR。

我能够 运行 下面的代码成功 而无需 额外的 OR 语句

示例:

SELECT
    * 
FROM
    USERS
WHERE
(
    DATE_OF_BIRTH IS NOT NULL 
    AND DBO.JAROWINKLER(CONVERT(VARCHAR(6),DATE_OF_BIRTH,12),@DOB) > 0.9
)
OR
(
    USERID = @USERID
)

然而,当我包含 OR 语句时,我收到此错误消息:

A .NET Framework error occurred during execution of user-defined routine or aggregate "JaroWinkler":

System.NullReferenceException: Object reference not set to an instance of an object. System.NullReferenceException: at JaroWinklerDistanceCLR.JaroWinklerDistance.proximity(String aString1, String aString2)

下面的代码可以工作并且可以完成所需的工作。我只是想知道是否有另一种方法?理想情况下,我希望它包含在一个 SELECT 语句中。我不知道上面的错误指的是什么,UserID 列中没有 NULL 值。

程序集的权限设置为安全。

工作示例:

SELECT
    *
FROM
    USERS
WHERE
    DATE_OF_BIRTH IS NOT NULL 
    AND DBO.JAROWINKLER(CONVERT(VARCHAR(6),DATE_OF_BIRTH,12),@DOB) > 0.9

UNION ALL

SELECT
    *
FROM
    USERS
WHERE
    USERID = @USERID

OR 语句很可能将 NULL 值包含到作为不同数据类型返回的结果集中。尝试使用

    OR (USERID = @USERID AND AND P.DATE_OF_BIRTH IS NOT NULL)

或者,如果您需要 NULL 值,则 select 字段名称显式(而不是 select *)并将 date_of_birth 字段包装在转换语句中

谢谢。 NULL 出生日期字段中的值。

工作中!

SELECT
    * 
FROM
    USERS
WHERE
(
    DBO.JAROWINKLER(CONVERT(VARCHAR(6),ISNULL(P.DATE_OF_BIRTH,''),12),@DOB) > 0.9
)
OR
(
    USERID = @USERID
)

其他两个答案是解决方法,而不是解决方案。而且这个变通办法必须在每个使用这个函数的地方重复,这很容易出错并且难以维护。

在进入主要问题之前,有一个相关的小问题需要先解决:输入参数类型不正确。对于 SQLCLR 方法,您应该使用 Sql* 类型而不是标准的 .NET 类型。对于这个特定的代码,这意味着使用 SqlString 而不是 String。为什么SqlString而不是String,请看我对下面S.O的回答。问题:Should I use SqlString or string as parameter type to SQLCLR UDF's.

现在,问题是 SQLCLR 代码没有正确处理 NULLs。幸运的是,让它处理它们并不难。有两个选项,取决于输入参数的 any 是否可以接受 NULL

  • 如果任何的入参都可以有效传入一个NULL,那么你需要在代码中处理这个(这也是适用于使用 Table-Valued Functions 和 Stored Procedures 时的所有情况)。然后您通过所有 Sql* 类型都具有的 .IsNull 属性 签入代码。例如(假设aString2可以传入一个NULL):

    if (aString1.IsNull)
    {
      return SqlDouble.Null;
    }
    
  • 如果none的输入参数可以有效地接受NULL,那么你应该绕过所有处理而不输入代码首先通过使用 CREATE FUNCTION 语句的 WITH RETURNS NULL ON NULL INPUT 选项创建标量 UDF。设置此选项后,如果 any 输入参数为 NULL,则跳过代码并假定 NULL return 值。请注意,这仅适用于标量 UDF 和用户定义类型方法。

有关一般使用 SQLCLR 的更多信息,请参阅我在 SQL Server Central 上就此主题撰写的系列文章(需要免费注册才能阅读其中的内容站点): Stairway to SQLCLR.


在相关说明中,我质疑使用字符串距离函数来执行相当简单的日期计算。我认为这段代码将从基于将字符串 @DOB 转换为 DATEDATETIME.

DATEDIFF 替换 JaroWinkler 函数中受益匪浅