2012-05-22 5 views
6

をデータから列を数える(同上、...、ToatlViews int型)とItemViews(ID、アイテムID、タイムスタンプ)私はすべてのビューを保存ItemViewsテーブルで更新私は2つのテーブルのアイテムを持っている別のテーブルに私のDBで

彼らがサイトに来るときのアイテム。私は時々、Items.ToatlViewsフィールドを更新するストアドプロシージャを呼び出す必要があります。カーソルを使ってこのSPを実行しようとしましたが、更新ステートメントが間違っています。それを修正するのを助けてくれますか?カーソルなしでこれを行うことはできますか?

CREATE PROCEDURE UpdateItemsViews 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    DECLARE @currentItemId int 
    DECLARE @currentItemCursor CURSOR 
    SET @currentItemCursor = CURSOR FOR SELECT Id FROM dbo.Items 

    OPEN @currentItemCursor 
    FETCH NEXT FROM @currentItemCursor INTO @currentItemId 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     Update dbo.Items set TotalViews = count(*) 
       from dbo.ItemViews where [email protected] 
     FETCH NEXT FROM @currentItemCursor INTO @currentItemId 
    END 
END 
GO 
+0

は、私はそれは、誰かがコードを実行し忘れの可能性がないとして、再計算を行うために、手動で何かを実行するよりもよりよい解決策だと思いますSQLを書くときにはカーソルを使わないように努力することをお勧めします。データベースに対して必要なものを書くための 'set'ベースの方法が常に存在するためです。もちろん、このルールには常に例外があります。エレガンスのために –

答えて

18

をあなたは直接UPDATEステートメントを使用することができます

update Items set TotalViews = 
    (select COUNT(id) from ItemViews where ItemViews.ItemId = Items.Id) 

あなたはこれを行うためのさまざまな方法のためのパフォーマンスをテストすることをお勧めしますそれが重要なのならば。

+0

+1。パフォーマンスについて話す。私はどこかで、 'count(id)'の代わりに 'count(1)'が良いことを読んでいることを覚えています。 IDフィールドはクエリの一部として選択する必要があるため、 –

+1

@moutersは誤解です。 'COUNT(1)'は正確性について言えば 'COUNT(id)'よりも優れているだけであり、 'id'がヌル入力可能であればより正確です。これがあなたの記憶以外のどこかに書かれているのを見たら、それを訂正したり明確にしなければならないので、指摘してください。 –

+0

公正なコメント - 私は記事を再び見つけるのが難しいと思う。 –

8

あなたはカーソルの代わりにupdate ... fromを使用することもできます。

update i 
set  TotalViews = iv.cnt 
from dbo.Item i 
join (
     select ItemId 
     ,  count(*) as cnt 
     from dbo.ItemViews 
     group by 
       ItemId 
     ) iv 
on  i.Id = iv.ItemId 
2
;WITH x AS 
(
    SELECT ItemID, c = COUNT(*) 
    FROM dbo.ItemViews 
    GROUP BY ItemID 
) 
UPDATE i 
SET TotalViews = x.c 
FROM dbo.Items AS i 
INNER JOIN x 
ON x.ItemID = i.ItemID; 

なぜ、この値をいつ実行時にいつでも得ることができますか?何らかの方法でItemViewsテーブルをタッチするたびに、この更新ステートメントを実行する必要があります。そうしないと、Itemsで保存されたカウントが正しくありません。

CREATE VIEW dbo.ItemViewCount 
WITH SCHEMABINDING 
AS 
    SELECT ItemID, ItemCount = COUNT_BIG(*) 
     FROM dbo.ItemViews 
     GROUP BY ItemID; 
GO 
CREATE UNIQUE CLUSTERED INDEX x ON dbo.ItemViewCount(ItemID); 

を今、あなたはあなたのクエリ内のビューに参加して、カウントが常に最新であることを知ることができる(の違約金を支払うことなく:あなたがインデックス付きビューを設定している代わりにやって考えることができる何を

各項目の数をスキャンする)。インデックス付きビューの欠点は、ItemViewsテーブルへの挿入/更新/削除がある場合に、そのコストを段階的に支払うことです。

0

この質問/回答は、書面で回答してから1年後に見つかりました。答えは大丈夫でしたが、もう少し自動化されました。私は、他のテーブルの関連する行が挿入、削除、または更新されたときに自動的に列を再計算するトリガーを作成しました。

CREATE TRIGGER [dbo].[TriggerItemTotalViews] 
    ON [dbo].[ItemViews] 
    AFTER INSERT, DELETE, UPDATE 
AS 
BEGIN 
SET NOCOUNT ON; 

UPDATE [Items] 
SET [TotalViews] = 
    (
    SELECT COUNT(id) 
    FROM [ItemViews] 
    WHERE [ItemViews].[ItemId] = [Items].[ItemId] 
    ) 
WHERE [Items].[ItemId] IN 
    (
    SELECT [ItemId] FROM [INSERTED] 
    UNION 
    SELECT [ItemId] FROM [DELETED] 
    ) 
END 
0

同じですが、異なる:

declare @productId int = 24; 
declare @classificationTypeId int = 86; 

update s 
set CounterByProductAndClassificationType = row_num 
from Samples s 
join 
(
    select row_number() over (order by (select Id)) row_num, Id 
    from Samples 
    where 
     ProductId = @productId and 
     ClassificationTypeId = @classificationTypeId 
) s_row on s.Id = s_row.Id 
関連する問題