我有一个表,该表毫无意义地将DateTime值存储在Year(INT
),Month(INT
),Day(INT
)和Time(FLOAT
)列中;不幸的是,我不允许更改此设置,但要求按年和月对表进行分区。因此,我试图创建一个持久化的计算列,以DATETIME2
格式保存DateTime。但是,当我尝试根据其标量添加计算列时,我的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
?
答案 0 :(得分:2)
通过绕过我的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
解决方案中存在的舍入误差无效。