无法使计算列可索引

时间:2018-10-04 11:45:21

标签: sql-server indexing deterministic non-deterministic

CREATE FUNCTION dbo.FN_GET_YEAR(@ID int) RETURNS int WITH SCHEMABINDING AS
BEGIN
    RETURN (SELECT YEAR(begin_date) FROM dbo.tableName WHERE id = @ID);
END

GO

CREATE TABLE test_table (
    id int,
    fk_id int,
    test AS dbo.FN_GET_YEAR(id)
);

SELECT COLUMNPROPERTY(OBJECT_ID('test_table'), 'test', 'IsIndexable') AS IsIndexableColumn;

以上是我实际问题的非常简化的摘录。我有一个函数,该函数返回给定日期的年份,然后将该函数用作计算列。我希望计算列可索引。

但是,尽管在线尝试了所有建议,但我不确定自己缺少什么。我使用了“ WITH SCHEMABINDING”关键字,并且尝试使用和不使用CONVERT / CAST。问题在于该列不是确定性的,但是文档还说YEAR()是确定性的。

如果仅在函数中返回静态声明的值,则该列将变为可索引的。 YEAR()似乎打破了它。

编辑:

我不想发布原始查询来使事情保持简单,但是也许我做得太简单了。我更新了函数查询,使其更接近实际。

2 个答案:

答案 0 :(得分:2)

  

我有一个返回给定日期的年份的函数,然后将该函数用作计算列

这不是您发布的内容。您发布了一个返回当前年份的函数,这显然不是确定性的。

您可以编写返回给定日期的年份并将其用于索引的计算列的函数:

CREATE FUNCTION dbo.FN_GET_YEAR(@d datetime) RETURNS int WITH SCHEMABINDING AS
BEGIN
    RETURN YEAR(@d);
END

GO

CREATE TABLE test_table (
    id int,
    dateCol datetime,
    test AS dbo.FN_GET_YEAR(dateCol)
);

SELECT COLUMNPROPERTY(OBJECT_ID('test_table'), 'test', 'IsIndexable') AS IsIndexableColumn;

create index ix_test_table_test on test_table(test)

答案 1 :(得分:0)

  

“我需要将外键和年份组合限制为每年一次。因此它将是唯一索引。”

我不确定您要尝试的是一个好主意,但是肯定不能用计算列上的索引来强制执行,因为在 表中的更改都需要防止。

您可以使用索引视图来执行此类操作。 EG:

drop view if exists v_test_table_year
drop table if exists test_table
drop table if exists tablename
go
create table tableName(id int, begin_date datetime)

go

CREATE TABLE test_table (
    id int,
    fk_id int--,
   -- test AS dbo.FN_GET_YEAR(id)
);

go
create or alter view v_test_table_year
with schemabinding
as
select year(tn.begin_date) year
from dbo.test_table t
join dbo.tableName tn
  on t.fk_id = tn.id

 go
 create unique clustered index ci_v_test_table_year
 on v_test_table_year(year)

 go

 insert into tableName(id,begin_date) values (1,'2017-01-01')
 insert into tableName(id,begin_date) values (2,'2017-02-01')

 insert into test_table(id,fk_id) values (1,1) --ok
 insert into test_table(id,fk_id) values (2,2) --fails