Функция SQL CLR для замены TRY_CONVERT

Я пытаюсь написать свою собственную функцию CLR, чтобы заменить встроенную функцию sql "TRY_CONVERT", поскольку мне нужно больше контролировать преобразование дат и чисел (например, встроенная функция не может обрабатывать преобразования DECIMAL, которые содержат научную нотацию).

Я пробовал это:

[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static object TRY_CONVERT(SqlDbType type, SqlString input)
{
    switch (type)
    {
        case SqlDbType.Decimal:
            decimal decimalOutput;
            return decimal.TryParse(input.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out decimalOutput) ? decimalOutput : (decimal?)null;
        case SqlDbType.BigInt:
            long bigIntOutput;
            return long.TryParse(input.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out bigIntOutput) ? bigIntOutput : (long?)null;
        case SqlDbType.Date:
        case SqlDbType.DateTime:
        case SqlDbType.DateTime2:
            DateTime dateTimeOutput;
            return DateTime.TryParse(input.Value, CultureInfo.CreateSpecificCulture("en-GB"), DateTimeStyles.None, out dateTimeOutput) ? dateTimeOutput : (DateTime?)null;
        case SqlDbType.NVarChar:
        case SqlDbType.VarChar:
            return string.IsNullOrWhiteSpace(input.Value) ? null : input.Value;
        default:
            throw new NotImplementedException();
    }
}

но мне не нравится тип SqlDbType при сборке.

Можно ли передать «target_type», используемый во встроенной функции, или мне придется передать его в виде строки или создать отдельные методы TRY_CONVERT для каждого типа, который я хочу использовать?


person Piers Myers    schedule 30.04.2014    source источник


Ответы (1)


Тип возвращаемого значения object преобразуется в sql_variant, поэтому его необходимо явно преобразовать в правильный тип данных в SQL, поэтому я думаю, что единственный способ решить эту проблему — создать отдельные методы CLR, которые имеют правильные возвращаемые типы, например:

[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static SqlDecimal TRY_CONVERT_DECIMAL(SqlString input)
{
    decimal decimalOutput;
    return !input.IsNull && decimal.TryParse(input.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out decimalOutput) ? decimalOutput : SqlDecimal.Null;
}

[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static SqlInt64 TRY_CONVERT_BIGINT(SqlString input)
{
    long bigIntOutput;
    return !input.IsNull && long.TryParse(input.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out bigIntOutput) ? bigIntOutput : SqlInt64.Null;
}

[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static SqlDateTime TRY_CONVERT_DATE(SqlString input)
{
    var minSqlDateTime = new DateTime(1753, 1, 1, 0, 0, 0, 0);
    var maxSqlDateTime = new DateTime(9999, 12, 31, 23, 59, 59, 0);
    DateTime dateTimeOutput;
    return !input.IsNull && DateTime.TryParse(input.Value, CultureInfo.CreateSpecificCulture("en-GB"), DateTimeStyles.None, out dateTimeOutput) &&
        dateTimeOutput >= minSqlDateTime && dateTimeOutput <= maxSqlDateTime ? dateTimeOutput : SqlDateTime.Null;
}

[SqlFunction(IsDeterministic = true, IsPrecise = true)]
public static SqlString TRY_CONVERT_NVARCHAR(SqlString input)
{
    return input.IsNull || string.IsNullOrWhiteSpace(input.Value) ? SqlString.Null : input.Value;
}
person Piers Myers    schedule 01.05.2014
comment
Я согласен, что это лучший подход. Поскольку API SQLCLR не допускает перегрузку, у вас действительно нет особого выбора. Использование object / SQL_VARIANT также проблематично, поскольку, по крайней мере, для многих или даже большинства целевых типов данных существует определенное снижение производительности. - person Solomon Rutzky; 03.09.2015