Есть ли "Try" равнозначно DATETIME2FROMPARTS? - PullRequest
0 голосов
/ 28 мая 2019

Учитывая следующие поля:

Y INT, --Year.
M INT, --Month.
D INT, --Day.
T FLOAT --Hours (H), minutes (m), seconds (s) and milliseconds (x) (in the form HHmmss.xxx).

Есть ли способ попытка преобразовать эти значения в DATETIME2 без необходимости их предварительного преобразованияк строковому типу данных?Если попытка не удалась (например, из-за переполнения значения дня (например, 35 января 2019 г.)), я бы хотел, чтобы было возвращено NULL.

Если я использую DATETIME2FROMPARTS, он просто потерпит неудачу, если пройдетнедопустимый компонент.

Я пытаюсь избежать преобразования их в строку, поскольку единственная причина, по которой я пытаюсь использовать это скомпрометированное решение, заключается в том, что производительность моего другого решения, которое фактически обрабатывает переполнение и недостаточное выполнение, невероятно медленна по сравнению с большимбазы данных (не завершается через 5 часов!), поэтому я пытаюсь попробовать что-то попроще, чтобы увидеть, улучшает ли это производительность добавления этого в виде вычисляемого постоянного столбца.

1 Ответ

2 голосов
/ 28 мая 2019

Вот специальное решение, которое я написал для этого.К сожалению, есть повторяющаяся логика, так как я использую это в постоянном вычисляемом столбце и, следовательно, не могу использовать переменные или скалярные функции (для параметров, которые будут использоваться в качестве переменных).

DECLARE @Y INT = 2000, @M INT = 2, @D INT = 29, @T FLOAT = 135559.999

SELECT IIF
    (
        --If the Year is out-of-bounds.
        @Y <= 0 OR @Y > 9999
        --Or the Month is out-of-bounds.
        OR @M <= 0 OR @M > 12
        --Or the Day is out-of-bounds (Accounts for leap years).
        OR @D <= 0 OR @D > DAY(EOMONTH(DATETIME2FROMPARTS(@Y, @M, 1, 0, 0, 0, 0, 3)))
        --Or the Time is less than 0
        OR @T < 0
        --Or the Hour is out-of-bounds.
        OR ROUND(@T / 10000, 0, 1) >= 24
        --Or the Minute is out-of-bounds.
        OR ROUND(@T / 100, 0, 1) - ROUND(@T / 10000, 0, 1) * 100 >= 60
        --Or the Second is out-of-bounds.
        OR ROUND(@T, 0, 1) - ROUND(@T / 100, 0, 1) * 100 >= 60,
        --NULL is returned
        NULL,
        --Otherwise, the Date Time components are parsable into a DATETIME2.
        DATETIME2FROMPARTS
        (
            --Year
            @Y,
            --Month
            @M,
            --Day
            @D,
            --Hour
            ROUND(@T / 10000, 0, 1),
            --Minute
            ROUND(@T / 100, 0, 1) - ROUND(@T / 10000, 0, 1) * 100,
            --Second
            ROUND(@T, 0, 1) - ROUND(@T / 100, 0, 1) * 100,
            --Millisecond (multiplied by 1000 to use the first 3 decimal places).
            (@T - ROUND(@T, 0, 1)) * 1000,
            --Precision (3 is specified since only 3 decimal places become part of the integer for the fraction parameter above).
            3
        )
    )

Если вам нужна точность в миллисекундах, отличная от3 знака после запятой, где ваша точность в миллисекундах равна x, измените 3 на x и * 1000 в строке выше на * POWER(10, x).

...