2012-05-22 37 views
6

在我的數據庫我有兩個表項(ID,...,ToatlViews int)和ItemViews(ID,項目Id,時間戳)更新另一個表計數從數據列

在ItemViews表我存儲的所有視圖一個項目,因爲他們來到現場。我不時想調用存儲過程來更新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(1)'而不是'count(id)'更好(不是你可能會注意到它)。由於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

我在寫作和回答一年後才發現此問題/答案。答案是可以的,但是我是在一些更自動化之後。當我插入,刪除或更新另一個表中的相關行時,我最終編寫了一個觸發器來自動重新計算列。

我覺得它比手動運行的東西做重新計算,因爲沒有的人忘記運行代碼的任何可能性,更好的解決方案:

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 
相關問題