2012-05-22 40 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 
相关问题