带子查询的持久计算列

时间:2011-03-11 17:00:38

标签: sql-server calculated-columns

我有类似的东西

create function Answers_Index(@id int, @questionID int)
returns int
as begin
    return (select count([ID]) from [Answers] where [ID] < @id and [ID_Question] = @questionID)
end
go

create table Answers
(
    [ID] int not null identity(1, 1),
    [ID_Question] int not null,
    [Text] nvarchar(100) not null,
    [Index] as [dbo].[Answers_Index]([ID], [ID_Question]),
)
go

insert into Answers ([ID_Question], [Text]) values
    (1, '1: first'),
    (2, '2: first'),
    (1, '1: second'),
    (2, '2: second'),
    (2, '2: third')

select * from [Answers]

哪种方法效果很好,但它往往会减慢查询速度。如何使列Index保持不变?我试过以下:

create table Answers
(
    [ID] int not null identity(1, 1),
    [ID_Question] int not null,
    [Text] nvarchar(100) not null,
)
go

create function Answers_Index(@id int, @questionID int)
returns int
with schemabinding
as begin
    return (select count([ID]) from [dbo].[Answers] where [ID] < @id and [ID_Question] = @questionID)
end
go

alter table Answers add [Index] as [dbo].[Answers_Index]([ID], [ID_Question]) persisted
go

insert into Answers ([ID_Question], [Text]) values
    (1, '1: first'),
    (2, '2: first'),
    (1, '1: second'),
    (2, '2: second'),
    (2, '2: third')

select * from [Answers]

但是会引发以下错误:Computed column 'Index' in table 'Answers' cannot be persisted because the column does user or system data access.或者我应该忘记它并使用[Index] int not null default(0)并将其填入on insert触发器中?

编辑:谢谢,最终解决方案:

create trigger [TRG_Answers_Insert]
on [Answers]
for insert, update
as
    update [Answers] set [Index] = (select count([ID]) from [Answers] where [ID] < a.[ID] and [ID_Question] = a.[ID_Question])
        from [Answers] a 
        inner join [inserted] i on a.ID = i.ID      
go

2 个答案:

答案 0 :(得分:4)

您可以将列更改为普通列,然后在使用触发器对该行进行INSERT / UPDATE时更新其值。

create table Answers
(
[ID] int not null identity(1, 1),
[ID_Question] int not null,
[Text] nvarchar(100) not null,
[Index] Int null
)

CREATE TRIGGER trgAnswersIU
ON Answers
FOR INSERT,UPDATE
AS 
   DECLARE @id int
   DECLARE @questionID int
   SELECT @id = inserted.ID, @questionID = inserted.ID_question


  UPDATE Answer a
  SET Index = (select count([ID]) from [Answers] where [ID] < @id and [ID_Question] = @questionID)
  WHERE a.ID = @id AND a.ID_question = @questionID

GO

NB *这不完全正确,因为它在UPDATE上无法正常工作,因为我们没有“插入”表来引用获取ID和questionid。有一种解决方法,但我现在无法记住它:(

Checkout this for more info

答案 1 :(得分:0)

计算列仅存储要执行的计算公式。这就是为什么从表中查询计算列时速度会变慢的原因。如果要将值保存到实际的表列,那么使用触发器是正确的。