2011-03-11 2 views
6

У меня есть что-то вроде этогосохранялось вычисляемый столбец с подзапроса

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 
+0

Честно говоря, я не совсем уверен, что я понимаю, что вы пытаетесь решить? - это выбрать запрос медленный Это не касается вашего столбца «index», поэтому я не вижу, насколько это важно - хотя вы можете добавить индекс или два ... –

ответ

4

Вы можете изменить столбец как обычный столбец, а затем обновить его значение, когда вы вставляете/обновляете эту строку с помощью триггера.

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, как мы не будем иметь «вставить» таблицу для ссылки, чтобы получить идентификатор и QuestionID. Существует способ обойти это, но я не могу вспомнить его прямо сейчас :(

Checkout this for more info

+0

Это не учитывает несколько строк INSERT/UPDATE. –

0

Вычисляемые столбцы только сохранить формулу расчета для выполнения. Поэтому при запросе вычисленного столбца из таблицы он будет медленнее. Если вы хотите сохранить значения в фактическом столбце таблицы, то вы правильно используете триггер.

+3

Персистентные вычисленные столбцы должны сохранять вычисленное значение (они обнаруживают необходимость обновления связанный с привязкой к схеме) ... проблема заключается в общих ограничениях с вычисленными столбцами (и, более того, с постоянными вычисленными столбцами). –

 Смежные вопросы

  • Нет связанных вопросов^_^