2011-03-11 30 views
6

Tôi có một cái gì đó như thế nàytồn tính cột với subquery

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] 

Những công trình vĩ đại, tuy nhiên nó có xu hướng chậm các truy vấn khá một chút. Làm thế nào tôi có thể làm cho cột Index tiếp tục tồn tại? Tôi đã thử sau:

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] 

Nhưng đó ném lỗi sau: Computed column 'Index' in table 'Answers' cannot be persisted because the column does user or system data access. Hoặc nên tôi chỉ quên nó đi và sử dụng [Index] int not null default(0) và điền nó trong on insert kích hoạt?

chỉnh sửa: cảm ơn bạn, giải pháp cuối cùng:

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

Thành thật mà nói, tôi không hoàn toàn chắc chắn tôi hiểu những gì bạn đang cố gắng để giải quyết - là chọn truy vấn chậm Nó không chạm vào cột "chỉ mục" của bạn, vì vậy tôi không thấy mức độ liên quan - mặc dù bạn có thể muốn thêm một hoặc hai chỉ mục ... –

Trả lời

4

Bạn có thể thay đổi cột thành cột bình thường và sau đó cập nhật giá trị của cột khi bạn INSERT/UPDATE hàng đó bằng trình kích hoạt.

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 * Điều này không hoàn toàn chính xác vì nó không hoạt động chính xác vào UPDATE vì chúng tôi sẽ không có bảng "được chèn" để tham chiếu để nhận ID và câu hỏi. Có một khoảng cách này nhưng tôi không thể nhớ nó ngay bây giờ :(

Checkout this for more info

+0

Điều này không được tính cho nhiều hàng INSERT/UPDATE. –

0

cột Tính toán chỉ lưu trữ các công thức của việc tính toán để thực hiện. Đó là lý do tại sao nó sẽ chậm hơn khi truy vấn cột được tính từ bảng. Nếu bạn muốn tồn tại các giá trị cho một cột bảng thực tế, thì bạn chính xác về việc sử dụng trình kích hoạt.

+3

Cột được tính toán ổn định sẽ lưu giá trị được tính toán (chúng phát hiện nhu cầu cập nhật theo bị ràng buộc lược đồ) ... vấn đề là những hạn chế chung với các cột được tính toán (và nhiều hơn nữa với các cột được tính toán liên tục) –