Как использовать переменные в постоянном вычисляемом столбце? - PullRequest
0 голосов
/ 24 мая 2019

У меня есть постоянный вычисляемый столбец, который я использую для хранения DATETIME2, вычисленного по столбцу времени FLOAT ([Потенциально плохое время]). Я обрабатываю недопустимые значения и переполнение всех компонентов времени, используя DATEADD, но в настоящее время мне приходится пересчитывать одни и те же значения по всей формуле, потому что я не могу понять, как сохранить их в переменной! Реальная реализация также поддерживает год, месяц и день, но содержит 210 строк, поэтому здесь урезанная версия, использующая только временные компоненты

CREATE TABLE Sales
(
    [Id] INT IDENTITY(1,1) NOT NULL,
    [Potentially Bad Time] FLOAT NOT NULL,
    CONSTRAINT PK_Sales PRIMARY KEY
    (
        Id ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE Sales
ADD [Time] AS
    DATEADD
    (
        HOUR,
        IIF
        (
            ROUND([Potentially Bad Time] / 10000, 0, 1) < 0,
            --Subtracts underflowing hours.
            ROUND([Potentially Bad Time] / 10000, 0, 1),
            IIF
            (
                ROUND([Potentially Bad Time] / 10000, 0, 1) >= 24,
                --Adds overflowing hours.
                ROUND([Potentially Bad Time] / 10000, 0, 1) - 24,
                0
            )
        ),
        DATEADD
        (
            MINUTE,
            IIF
            (
                ROUND([Potentially Bad Time] / 100, 0, 1) - ROUND([Potentially Bad Time] / 10000, 0, 1) * 100 < 0,
                --Subtracts underflowing minutes.
                ROUND([Potentially Bad Time] / 100, 0, 1) - ROUND([Potentially Bad Time] / 10000, 0, 1) * 100,
                IIF
                (
                    ROUND([Potentially Bad Time] / 100, 0, 1) - ROUND([Potentially Bad Time] / 10000, 0, 1) * 100 >= 60,
                    --Adds overflowing minutes.
                    ROUND([Potentially Bad Time] / 100, 0, 1) - ROUND([Potentially Bad Time] / 10000, 0, 1) * 100 - 60,
                    0
                )
            ),
            DATEADD
            (
                SECOND,
                --If the seconds value is greater than or equal to 60, this adds on the overflowing seconds to the relevant DATETIME2 component(s).
                IIF
                (
                    ROUND([Potentially Bad Time], 0, 1) - ROUND([Potentially Bad Time] / 100, 0, 1) * 100 < 0,
                    --Subtracts underflowing seconds.
                    ROUND([Potentially Bad Time], 0, 1) - ROUND([Potentially Bad Time] / 100, 0, 1) * 100,
                    IIF
                    (
                        ROUND([Potentially Bad Time], 0, 1) - ROUND([Potentially Bad Time] / 100, 0, 1) * 100 >= 60,
                        --Adds overflowing seconds.
                        ROUND([Potentially Bad Time], 0, 1) - ROUND([Potentially Bad Time] / 100, 0, 1) * 100 - 59,                 
                        0
                    )
                ),
                DATEADD
                (
                    MILLISECOND,
                    IIF
                    (
                        [Potentially Bad Time] - ROUND([Potentially Bad Time], 0, 1) < 0,
                        --Subtracts underflowing milliseconds.
                        [Potentially Bad Time] - ROUND([Potentially Bad Time], 0, 1),
                        IIF
                        (
                            [Potentially Bad Time] - ROUND([Potentially Bad Time], 0, 1) > 9999999,
                            --Adds overflowing milliseconds.
                            [Potentially Bad Time] - ROUND([Potentially Bad Time], 0, 1) - 9999999,
                            0
                        )
                    ),
                    DATETIME2FROMPARTS
                    (
                        --Year (Fixed for brevity of example)
                        1990,
                        --Month (Fixed for brevity of example)
                        12,
                        --Day (Fixed for brevity of example).
                        31,
                        --Hour
                        IIF
                        (
                            ROUND([Potentially Bad Time] / 10000, 0, 1) < 0,
                            0,
                            IIF
                            (
                                ROUND([Potentially Bad Time] / 10000, 0, 1) >= 24,
                                23,
                                ROUND([Potentially Bad Time] / 10000, 0, 1)
                            )
                        ),
                        --Minute
                        IIF
                        (
                            ROUND([Potentially Bad Time] / 100, 0, 1) - ROUND([Potentially Bad Time] / 10000, 0, 1) * 100 < 0,
                            0,
                            IIF
                            (
                                ROUND([Potentially Bad Time] / 100, 0, 1) - ROUND([Potentially Bad Time] / 10000, 0, 1) * 100 >= 60,
                                59,
                                ROUND([Potentially Bad Time] / 100, 0, 1) - ROUND([Potentially Bad Time] / 10000, 0, 1) * 100
                            )
                        ),
                        --Second
                        IIF
                        (
                            --If the seconds value is less than 0, truncates it to 0.
                            ROUND([Potentially Bad Time], 0, 1) - ROUND([Potentially Bad Time] / 100, 0, 1) * 100 < 0,
                            0,
                            --If the seconds value is greater than or equal to 60, this truncates it at 59.
                            IIF
                            (
                                ROUND([Potentially Bad Time], 0, 1) - ROUND([Potentially Bad Time] / 100, 0, 1) * 100 >= 60,
                                59,
                                ROUND([Potentially Bad Time], 0, 1) - ROUND([Potentially Bad Time] / 100, 0, 1) * 100
                            )
                        ),
                        --Millisecond
                        IIF
                        (
                            [Potentially Bad Time] - ROUND([Potentially Bad Time], 0, 1) < 0,
                            0,
                            IIF
                            (
                                [Potentially Bad Time] - ROUND([Potentially Bad Time], 0, 1) > 9999999,
                                9999999,
                                [Potentially Bad Time] - ROUND([Potentially Bad Time], 0, 1)
                            )
                        ),
                        3
                    )
                )
            )
        )
    )
PERSISTED

Как можно, например, поместить [Time] - ROUND([Time], 0, 1) в переменную с именем @milliseconds, чтобы сохранить ее вычисление несколько раз?

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

Я также пробовал DECLARE @milliseconds FLOAT = [Time] - ROUND([Time], 0, 1) между AS и формулой, но это синтаксическая ошибка.

1 Ответ

0 голосов
/ 24 мая 2019

Вам нужно добавить select, чтобы присвоить значение вашей переменной.

DECLARE @milliseconds FLOAT = ( select [Time] - 
ROUND([Time], 0, 1) from yourtable);
...