2011-03-11 15 views
6

ho qualcosa di similepersistenti In colonna calcolata con sottoquery

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] 

Quali grandi opere, tuttavia tende a rallentare le query un po '. Come posso rendere persistente la colonna Index? Ho provato seguente:

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] 

Ma che getta seguente errore: Computed column 'Index' in table 'Answers' cannot be persisted because the column does user or system data access. O devo solo dimenticare e utilizzare [Index] int not null default(0) e riempirlo in on insert grilletto?

edit: grazie, soluzione finale:

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

Per essere onesti, non sono del tutto sicuro di capire quello che stai cercando di risolvere -? È la query di selezione lento non tocca la colonna "indice", quindi non vedo come ciò sia rilevante, anche se potresti voler aggiungere un indice o due ... –

risposta

4

È possibile modificare la colonna in modo che sia una colonna normale e quindi aggiornarne il valore quando INSERT/UPDATE quella riga utilizzando un trigger.

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 * Questo non è completamente corretto in quanto non funzionerà correttamente sul UPDATE come abbiamo solito abbiamo la tabella "inserito" per fare riferimento per ottenere l'ID e QuestionID. C'è un modo per aggirare questo, ma non mi ricordo proprio ora :(

Checkout this for more info

+0

Questo non conta per più righe INSERT/UPDATE. –

0

colonne calcolate memorizzano solo la formula del calcolo da eseguire. Questo è il motivo per cui sarà più lento quando si esegue una query sulla colonna calcolata dalla tabella. Se si desidera mantenere i valori su una colonna della tabella effettiva, significa che si sta utilizzando un trigger.

+3

Le colonne calcolate persistenti dovrebbero salvare il valore calcolato (rilevano la necessità di aggiornare essendo legato allo schema) ... il problema sono le limitazioni generali con colonne calcolate (e molto altro ancora con colonne calcolate persistenti). –

Problemi correlati