(这与在 SQL server 中设置日期有关。)
是否存在确定性表达式来确定 DATETIME?当我将其用作计算列公式时:
DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0)
在该列上放置索引时出现错误:
无法创建索引,因为键列“EffectiveDate”不确定或不精确。
但是 DATEDIFF 和 DATEADD 根据定义都是确定性函数。问题在哪里?是否可以?
(这与在 SQL server 中设置日期有关。)
是否存在确定性表达式来确定 DATETIME?当我将其用作计算列公式时:
DATEADD(dd, DATEDIFF(dd, 0, [datetime_column]), 0)
在该列上放置索引时出现错误:
无法创建索引,因为键列“EffectiveDate”不确定或不精确。
但是 DATEDIFF 和 DATEADD 根据定义都是确定性函数。问题在哪里?是否可以?
我的猜测是,这是某种错误。在 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
您的列 [datetime_column] 的默认值是否设置为“getDate()”?
如果是这样,由于 getdate() 函数是不确定的,这将导致此错误...
用户定义的函数是确定性的还是非确定性的取决于函数的编码方式。用户定义的函数是确定性的,如果:
不满足这些条件的用户定义函数被标记为不确定的。用户定义的函数体中不允许内置的非确定性函数。
试试这个:
CAST(FLOOR(CAST([datetime_column] as FLOAT)) AS DateTime)
它应该比 CONVERT 选项快得多。
这是我回答原始问题的最佳答案:
试试这个:
/* 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)
我很确定(从内存中)计算的持久列上的索引从性能角度来看是有益的 - 我想你只需要尝试/测试你自己的特定用法
(希望我有帮助!)
看看Cade Roux 提出并回答的那个问题。也许解决方案是使用 WITH SCHEMABINDING 创建一个函数,然后在计算列中使用它
编辑
我了解您的目标是能够在该列上建立索引。
如果计算列无法做到这一点,那么唯一的选择可能是创建一个普通列并在每次更新它所基于的列时修改该列中的数据。(在触发器中说)
我建议稍微简单一些:
cast(cast([datetime_column] as int) as datetime)
但我怀疑你会遇到同样的问题。
现在,如果问题在于转换回日期时间,您可能需要考虑将cast([datetime_column] as int)
其用作单独的字段,仅用于索引。