2009-04-15 28 views
6

Để hiểu điều này dễ hiểu hơn, tôi sẽ trình bày cùng một vấn đề giống như một diễn đàn (ứng dụng thực tế không liên quan đến diễn đàn tại tất cả, nhưng tôi nghĩ rằng việc song song này dễ dàng hơn đối với hầu hết chúng ta, ứng dụng thực tế là một thứ rất cụ thể mà hầu hết các lập trình viên sẽ không hiểu (đó là ứng dụng dành cho các nhà thiết kế đồ họa hardcore)).Trình kích hoạt MS SQL Server để cập nhật xếp hạng mục và số phiếu bầu

Giả sử có bảng chuỗi lưu trữ thông tin về từng chuỗi diễn đàn và bảng chuỗi lưu trữ xếp hạng luồng cho mỗi người dùng (1-5). Để có hiệu quả, tôi đã quyết định cache mức trung bình và số phiếu bầu trong bảng chuỗi và trình kích hoạt có vẻ giống như ý tưởng hay để cập nhật nó (tôi đã từng làm những thứ như vậy trong mã ứng dụng thực tế). các mối nguy hiểm gỡ lỗi).

Như bạn đã biết, MS SQL Server không hỗ trợ trình kích hoạt được thực hiện trên mỗi hàng, nó phải là một câu lệnh. Vì vậy, tôi đã cố gắng xác định theo cách này:

CREATE TRIGGER thread_rating ON threadrating 
AFTER INSERT 
AS 
    UPDATE thread 
    SET 
     thread.rating = (thread.rating * thread.voters + SUM(inserted.rating))/(thread.voters + COUNT(inserted.rating)), 
     thread.voters = thread.voters + COUNT(inserted.rating) 
    FROM thread 
    INNER JOIN inserted ON(inserted.threadid = thread.threadid) 
    GROUP BY inserted.threadid 

nhưng tôi gặp lỗi cho mệnh đề "GROUP BY" (mà tôi mong đợi). Câu hỏi là, làm thế nào tôi có thể thực hiện công việc này?

Xin lỗi nếu câu hỏi là ngu ngốc, nhưng đây là lần đầu tiên tôi thực sự cố gắng sử dụng trình kích hoạt.

Thông tin bổ sung: Bảng chủ đề chứa threadid (int, khóa chính), đánh giá (float), cử tri (int) và một số trường khác không liên quan đến câu hỏi hiện tại. Bảng phân luồng chỉ chứa threadid (khóa ngoài), userid (khóa ngoài tới khóa chính của bảng người dùng) và xếp hạng (tinyint giữa 1 và 5).

Thông báo lỗi là "Cú pháp không đúng gần từ khóa 'GROUP'."

+0

khóa chính trên bàn là gì? –

+0

Đăng DML bảng và thông báo lỗi thực tế cũng sẽ giúp ích. –

Trả lời

2

Trước tiên, tôi khuyên bạn không trigger sử dụng.

Nếu bạn gặp lỗi cú pháp, hãy kiểm tra xem các số parens của bạn có được cân bằng cũng như begin/ends của bạn không. Trong trường hợp của bạn, bạn có end (ở cuối) nhưng không bắt đầu. Bạn có thể khắc phục điều đó chỉ cần xóa end.

Khi bạn khắc phục điều đó, bạn sẽ có thể gặp một số lỗi khác như "cột x, y, z không phải trong tổng hợp hoặc nhóm theo". Đó là bởi vì bạn có một số cột không có trong một trong hai. Bạn cần phải thêm thread.rating, thread.voters, v.v. vào nhóm của bạn hoặc thực hiện một số loại tổng hợp trên chúng.

Đây là tất cả giả định rằng có nhiều bản ghi có cùng một luồngID (nghĩa là, đó không phải là khóa chính). Nếu đó là không phải là trường hợp, thì mục đích của nhóm là gì?


Edit:

Tôi đang bối rối về lỗi cú pháp. Tôi đã làm việc xung quanh nó với một vài truy vấn phụ tương quan.Tôi đoán tại cấu trúc bảng của bạn để sửa đổi khi cần và thử điều này:

--CREATE TABLE ThreadRating (threadid int not null, userid int not null, rating int not null) 
--CREATE TABLE Thread (threadid int not null, rating int not null, voters int not null) 

ALTER TRIGGER thread_rating ON threadrating 
AFTER INSERT 
AS 

UPDATE Thread 
SET Thread.rating = 
    (SELECT (Thread.Rating * Thread.Voters + SUM(I.Rating))/(Thread.Voters + COUNT(I.Rating)) 
    FROM ThreadRating I WHERE I.ThreadID = thread.ThreadID) 
    ,Thread.Voters = 
    (SELECT Thread.Voters + COUNT(I.Rating) 
    FROM ThreadRating I WHERE I.ThreadID = Thread.ThreadID)       
FROM Thread 
JOIN Inserted ON Inserted.ThreadID = Thread.ThreadID 

Nếu đó là những gì bạn muốn, thì chúng tôi có thể kiểm tra hiệu suất/kế hoạch thực hiện và sửa đổi khi cần. Chúng tôi có thể làm cho nó hoạt động với nhóm theo.


Alternatives để gây

Nếu bạn đang cập nhật dữ liệu xếp hạng tác động chỉ trong một vài nơi lựa chọn, tôi khuyên bạn nên cập nhật xếp hạng trực tiếp ở đó. Tính toán logic vào một trigger là tốt đẹp nhưng cung cấp rất nhiều vấn đề (hiệu suất, khả năng hiển thị, vv). Điều này có thể được hỗ trợ bởi một hàm.

Hãy xem xét điều này: trình kích hoạt của bạn sẽ thực thi mỗi lần ai đó chạm vào bảng đó. Những thứ như số lượt xem, ngày cập nhật cuối cùng, v.v. sẽ thực thi trình kích hoạt này. Bạn có thể thêm logic để ngắn mạch kích hoạt trong những trường hợp đó nhưng nó trở nên phức tạp nhanh chóng.

+0

Có có thể là nhiều hàng với cùng một threadid trong bảng threading, không phải trong bảng thread Tôi mong đợi cùng một lỗi mà bạn đề cập đến, nhưng tôi đang nhận được một nhục nhã hơn "cú pháp sai gần từ khóa 'GROUP'" Nếu bạn don Không khuyến nghị kích hoạt, những gì bạn sẽ giới thiệu cho trường hợp này? –

+0

Xóa từ khóa "Kết thúc" ở cuối (hoặc thêm từ 'bắt đầu' sau 'dưới dạng') –

+0

Tôi chưa từng thấy bản chỉnh sửa trước đó. bảng phân luồng chỉ có 3 trường: threadid, userid, rating Bạn có thể xây dựng trên phần hiệu suất không? Tôi đã quyết định rằng toàn bộ khái niệm cho p lý do làm xáo trộn ... –

1

Bạn có thể tìm thấy những điều sau đọc hữu ích:

An introduction to Triggers
Wikipedia: DB Triggers

+0

Tôi đã đọc về trình kích hoạt và cách của SQL Server để thực hiện chúng trong ít nhất 3 giờ qua ... Không có gì giúp trường hợp cụ thể của tôi: ( –

+0

Wow, điều đó thật tệ! Tôi thấy mình có thể tìm thấy một số liên kết tốt hơn không. – Kredns

2

D'ohh! Tôi hoàn toàn hiểu sai câu hỏi của bạn và tôi nghĩ bạn đã hỏi về MySQL. Mea culpa! Tôi sẽ để nguyên giải pháp dưới đây, và đánh dấu nó là wiki cộng đồng. Có lẽ nó sẽ hữu ích cho ai đó với một vấn đề tương tự trên MySQL.


Trình kích hoạt MySQL được thi hành mỗi hàng. Ngoài ra, bảng giả "inserted" là một quy ước Microsoft SQL Server.

MySQL sử dụng các bảng giả NEWOLD làm tiện ích mở rộng cho trigger language.

Dưới đây là một giải pháp cho vấn đề của bạn:

CREATE TRIGGER thread_rating 
    AFTER INSERT ON threadrating 
    FOR EACH ROW 
BEGIN 
    UPDATE thread 
    SET rating = (rating*voters + NEW.rating)/(voters+1), 
     voters = voters + 1 
    WHERE threadid = NEW.threadid; 
END 

Tương tự như vậy bạn cần phải kích hoạt để UPDATEDELETE:

CREATE TRIGGER thread_rating 
    AFTER UPDATE ON threadrating 
    FOR EACH ROW 
BEGIN 
    UPDATE thread 
    SET rating = (rating*voters - OLD.rating + NEW.rating)/voters, 
    WHERE threadid = NEW.threadid; 
END 

CREATE TRIGGER thread_rating 
    AFTER DELETE ON threadrating 
    FOR EACH ROW 
BEGIN 
    UPDATE thread 
    SET rating = (rating*voters - OLD.rating)/(voters-1), 
     voters = voters - 1 
    WHERE threadid = OLD.threadid; 
END 
+0

Nhưng tôi đang sử dụng MS SQL Server! Mọi thứ sẽ dễ dàng hơn với MySQL, nhưng tôi không có lựa chọn nào cho dự án này: ( –

+0

D'ohh! Sai lầm của tôi. Xem phần chỉnh sửa ở trên cùng. –

+0

Np, nó chắc chắn sẽ hữu ích cho người khác :) –

Các vấn đề liên quan