2011-03-11 21 views
6

que tiene algo como estopersistentes de columna calculada con subconsulta

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] 

Qué funciona muy bien, sin embargo, tiende a ralentizar las consultas un poco. ¿Cómo puedo hacer que persista la columna Index? He tratado siguiente:

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] 

Pero eso arroja siguiente error: Computed column 'Index' in table 'Answers' cannot be persisted because the column does user or system data access. O debería olvidarse de él y utilizar [Index] int not null default(0) y llenarlo en on insert gatillo?

edición: gracias, solución final:

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

Para ser honesto, no estoy del todo seguro de entender lo que está tratando de resolver? - es la consulta de selección Se lenta no toca su columna de "índice", así que no veo cómo es relevante, aunque es posible que desee agregar un índice o dos ... –

Respuesta

4

Puede cambiar la columna para que sea una columna normal y luego actualizar su valor cuando INSERTA/ACTUALIZA esa fila usando un desencadenador.

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 * Esto no es totalmente correcta, ya que no funcionará correctamente en ACTUALIZACIÓN como no tendremos la mesa "insertada" para hacer referencia para obtener el ID y IdPregunta. Hay una forma de evitar esto, pero no puedo recordar que en este momento :(

Checkout this for more info

+0

Esto no se aplica a las filas múltiples INSERT/UPDATE. –

0

Las columnas calculadas sólo almacenan la fórmula del cálculo a realizar. Es por eso que será más lento al consultar la columna calculada desde la tabla. Si desea persistir los valores en una columna de tabla real, entonces tiene razón sobre el uso de un desencadenador.

+3

Las columnas calculadas persistentes deben guardar el valor calculado (detectan la necesidad de actualizar por estar vinculado al esquema) ... el problema son las limitaciones generales de las columnas calculadas (y más, por lo tanto, con las columnas calculadas persistentes). –

Cuestiones relacionadas