(这与Floor a date in SQL server有关。)
DATETIME是否存在确定性表达式?当我将其用作计算列公式时:
DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0)
当我在该列上放置索引时出现错误:
无法创建索引,因为键列'EffectiveDate'是非确定性的或不精确的。
但根据定义,DATEDIFF和DATEADD都是确定性函数。捕获量在哪里?有可能吗?
答案 0 :(得分:3)
我的猜测是,这是某种错误。在SQL 2005中,我能够创建这样的索引视图而没有问题(代码如下)。当我尝试在SQL 2000上运行它时,虽然我得到了与你相同的错误。
以下似乎适用于SQL 2000,但我收到一条警告,指出该索引将被忽略,并且每次从视图中选择时都必须进行转换。
CONVERT(CHAR(8), datetime_column, 112)
适用于SQL 2005:
CREATE TABLE dbo.Test_Determinism (
datetime_column DATETIME NOT NULL DEFAULT GETDATE())
GO
CREATE VIEW dbo.Test_Determinism_View
WITH SCHEMABINDING
AS
SELECT
DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0) AS EffectiveDate
FROM
dbo.Test_Determinism
GO
CREATE UNIQUE CLUSTERED INDEX IDX_Test_Determinism_View ON dbo.Test_Determinism_View (EffectiveDate)
GO
答案 1 :(得分:2)
您的列[datetime_column]是否将默认值设置为“getDate()”?
如果是这样,由于getdate()函数是非确定性的,这将导致此错误......
用户定义的函数是确定性的还是非确定性的取决于函数的编码方式。在以下情况下,用户定义的函数是确定的:
不符合这些条件的用户定义函数被标记为不确定。用户定义的函数体中不允许内置的非确定性函数。
答案 2 :(得分:1)
试试这个:
CAST(FLOOR(CAST([datetime_column] as FLOAT)) AS DateTime)
它应该比CONVERT选项快得多。
答案 3 :(得分:1)
这是回答原始问题的最佳答案:
试试这个:
/* create a deterministic schema bound function */
CREATE FUNCTION FloorDate(@dt datetime)
RETURNS datetime
WITH SCHEMABINDING
AS
BEGIN
RETURN CONVERT(datetime, FLOOR(CONVERT(float, @dt)))
END
GO
要进行测试,请尝试以下操作。请注意在计算列中使用“PERSISTED”以及在引用函数时使用[dbo。]
/*create a test table */
CREATE TABLE [dbo].[TableTestFloorDate](
[Id] [int] IDENTITY(1,1) NOT NULL,
[TestDate] [datetime] NOT NULL,
[TestFloorDate] AS ([dbo].[FloorDate]([TestDate])) PERSISTED,
CONSTRAINT [PK_TableTestFloorDate] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
您现在应该能够在计算列上添加索引(但稍后会看到问题)
CREATE INDEX IX_TestFloorDate ON [dbo].[TableTestFloorDate](TestFloorDate)
根据需要多次插入一些随机数据,但如果您希望测试索引使用/执行计划,则更多(1000+)更好
INSERT INTO TableTestFloorDate (TestDate) VALUES( convert(datetime, RAND()*50000))
获取结果
SELECT * FROM TableTestFloorDate WHERE TestFloorDate='2013-2-2'
现在这里是GOTCHA ...... 不使用在计算列上创建的索引!相反,即使在持久化字段TestFloorDate上选择数据,SQLServer(或至少我的版本)也更喜欢TestDate上的索引。
CREATE INDEX IX_TestFloorDate ON [dbo].[TableTestFloorDate](TestDate)
我很确定(从内存中)计算的,持久化的列上的索引可以从性能角度受益 - 我想你只需要尝试/测试你自己的特定用法
(希望我帮助过!)
答案 4 :(得分:0)
看看that question asked and answered by Cade Roux。也许解决方案是使用WITH SCHEMABINDING创建一个函数,然后在计算列
中使用它修改强>
我知道您的目标是能够在该列上拥有索引。
如果无法使用计算列完成,则可能唯一的选择是创建普通列,并在每次更新基于的列时修改该列中的数据。 (以触发器说)
答案 5 :(得分:0)
我建议稍微简化:
cast(cast([datetime_column] as int) as datetime)
但我怀疑你会遇到同样的问题。
现在,如果问题是回到日期时间,您可能要考虑仅将cast([datetime_column] as int)
用作单独的字段,仅用于索引。