我有一个表无意义地将DateTime值存储在Year(INT
),Month(INT
),Day(INT
)和Time(FLOAT
)列中;不幸的是,我不允许更改此内容,但需要按年份和月份对表进行分区。因此,我试图创建一个持久的计算列来保持日期时间为DATETIME2
格式。但是,当我尝试添加基于它的计算列时,我的CreateDateTime
标量函数被视为“非确定性”。
这是我的CreateDateTime
功能。
CREATE FUNCTION dbo.CreateDateTime
(
@year SMALLINT,
@month TINYINT,
@day TINYINT,
@time FLOAT
)
RETURNS DATETIME2
WITH SCHEMABINDING
AS
BEGIN
DECLARE @paddedYear VARCHAR(4) = FORMAT(@year, '0000')
DECLARE @paddedMonth VARCHAR(2) = FORMAT(@month, '00')
DECLARE @paddedDay VARCHAR(2) = FORMAT(@day, '00')
DECLARE @formattedTime VARCHAR(8) = FORMAT(@time, '00:00:00')
RETURN IIF
(
@year IS NULL
OR @month IS NULL
OR @day IS NULL,
NULL,
CAST
(
IIF
(
@time IS NULL OR TRY_CONVERT(TIME, @formattedTime) IS NULL,
@paddedYear
+ @paddedMonth
+ @paddedDay,
@paddedYear
+ @paddedMonth
+ @paddedDay
+ ' '
+ @formattedTime
)
AS DATETIME2
)
)
END
但是,当用于尝试为DateTime添加计算列(使用以下脚本)时,会导致以下错误消息。
ALTER TABLE dbo.Logs
ADD [DateTime] AS (dbo.CreateDateTime(RY, RM, RD, RT)) PERSISTED
表'Logs'中的计算列'DateTime'无法保留,因为该列是非确定性的。
我已经尝试将CreateDateTime
改为一个非常基本的函数,它使用以下函数返回一个固定的DateTime:CAST('20000101' AS DATETIME2)
,CONVERT(DATETIME2, '20000101')
和'20000101'
但都产生与上面相同的错误。我设法添加了列,但如果我使CreateDateTime
函数返回一个VARCHAR(8)
,所以它看起来像DATETIME2
的问题。
我如何创建这个CreateDateTime
函数,因此它被认为是确定性的,仍然返回一个DATETIME2
?
我能够通过绕过我的CreateDateTime
函数来创建持久化的计算列,而是使用以下内容:
ALTER TABLE dbo.Logs
ADD [DateTime] AS DATETIME2FROMPARTS
(
RY,
RM,
RD,
ROUND(RT / 10000, 0, 1),
ROUND(RT / 100, 0, 1) - ROUND(RT / 10000, 0, 1) * 100,
ROUND(RT, 0, 1) - ROUND(RT / 100, 0, 1) * 100,
RT - ROUND(RT, 0, 1),
3 --Precision to 3 decimal places (for milliseconds)
) PERSISTED
虽然这没有回答我关于创建一个返回DATETIME2
的确定性函数的问题;它确实解决了我创建一个DateTime2
持久计算列的具体问题,以显示每个RY,RM,RD和RT值的DateTime。
正如Zohar强调的那样,DATETIMEFROMPARTS
不会返回DATETIME2
; DATETIME2FROMPARTS
还为小数精度采用了一个附加参数 - 这使得我提供的原始DATETIMEFROMPARTS
解决方案中出现的舍入错误无效。