динамическое приведение в функции сервера SQL - PullRequest
0 голосов
/ 04 ноября 2019

Я хочу создать функцию, которая в основном будет принимать значения типа float или integer и преобразовывать их в десятичные числа определенной длины и точности.

Я написал код ниже, но, похоже, CAST не разрешает использование переменной DECIMAL:

CREATE OR ALTER FUNCTION dbo.DECI(@in as sql_variant,@len as int, @prec as int)
returns sql_variant
as
begin
     return CAST(@in as decimal(@len,@prec))
end

1 Ответ

0 голосов
/ 04 ноября 2019

Все комментарии под постом верны, однако, с тяжелой (и абсолютно бессмысленной) работой, вы действительно можете это сделать.

У вас есть функция, которая может преобразовывать в любой десятичный тип, который выуже хотите, они называются CAST и CONVERT, используйте их вместо этого!

НЕ ИСПОЛЬЗУЙТЕ ЭТО (если только вам это действительно не нужно) !! Этот ответ здесь, просто чтобы показать, что если вы хотите во что-то вкладывать работу, это обычно можно сделать тем или иным способом, но это не значит, что оно того стоит или если оно не будет создавать больше проблем, чем решает.

По моему мнению, реализовывать это абсолютно бессмысленно, обычно вам все равно придется снова приводить результат, и следующая реализация просто для развлечения (и, скорее всего, совершенно бесполезна, а производительностьдерьмо, когда оно используется в сочетании с чем-либо еще):

CREATE OR ALTER FUNCTION dbo.DECI(@in as SQL_VARIANT, @len as TINYINT, @prec as TINYINT)
RETURNS SQL_VARIANT
as
BEGIN
    DECLARE @ErrorResult DECIMAL(1,0) = NULL;

    RETURN
        CASE
            WHEN @len = 1 THEN
                CASE
                    WHEN @prec = 0 THEN CONVERT(DECIMAL(1,0), @in)
                    WHEN @prec = 1 THEN CONVERT(DECIMAL(1,1), @in)
                    ELSE @ErrorResult
                END
            WHEN @len = 2 THEN
                CASE
                    WHEN @prec = 0 THEN CONVERT(DECIMAL(2,0), @in)
                    WHEN @prec = 1 THEN CONVERT(DECIMAL(2,1), @in)
                    WHEN @prec = 2 THEN CONVERT(DECIMAL(2,2), @in)
                    ELSE @ErrorResult
                END
            WHEN @len = 3 THEN
                CASE
                    WHEN @prec = 0 THEN CONVERT(DECIMAL(3,0), @in)
                    WHEN @prec = 1 THEN CONVERT(DECIMAL(3,1), @in)
                    WHEN @prec = 2 THEN CONVERT(DECIMAL(3,2), @in)
                    WHEN @prec = 3 THEN CONVERT(DECIMAL(3,3), @in)
                    ELSE @ErrorResult
                END

            /* This goes on to @len = 38 */

            ELSE @ErrorResult
        END
END

Теперь заметки:

  • НЕ ДЕЛАЙТЕ ЭТОГО, просто не
  • Измените свой запрос вместо того, чтобы пытаться делать обходные пути, подобные этому. Вскоре вам придется прикасаться к коду из-за плохой производительности из-за ненужного приведения.
  • Неявное приведение из SQL_VARIANT к большинству типов недопустимо, поэтому в любом случае вам придется выполнять явные приведения в большинстве запросов

При попытке использовать это в (например) выражении INSERT

DECLARE @TestTable TABLE
(
    DecimalCol DECIMAL(3,2)
);

INSERT INTO @TestTable
(
    DecimalCol
)
VALUES
    (dbo.DECI(1.1, 3, 2))

Вы увидите следующее сообщение об ошибке:

Msg257, Уровень 16, Состояние 3, Строка 44 Неявное преобразование из типа данных sql_variant в десятичное не допускается. Используйте функцию CONVERT для выполнения этого запроса.

Теперь вам нужно обновить запрос:

INSERT INTO @TestTable
(
    DecimalCol
)
VALUES
    (CONVERT(DECIMAL(3,2), dbo.DECI(1.1, 3, 2)))

На данный момент, поздравляю, вы ничего не сделали, ноубийца производительности.

Делайте ваши вещи в запросе напрямую:

INSERT INTO @TestTable
(
    DecimalCol
)
VALUES
    (CONVERT(DECIMAL(3,2), 1.1))
...