У меня есть постоянный вычисляемый столбец, который я использую для хранения 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
и формулой, но это синтаксическая ошибка.