在我的数据库中我有两个表项(Id,...,ToatlViews int)和ItemViews(id,ItemId,Timestamp)
在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 ItemId=@currentItemId
FETCH NEXT FROM @currentItemCursor INTO @currentItemId
END
END
GO
答案 0 :(得分:21)
您可以使用直接UPDATE语句
update Items set TotalViews =
(select COUNT(id) from ItemViews where ItemViews.ItemId = Items.Id)
如果这很重要,您可能希望测试各种方法的性能。
答案 1 :(得分: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 :(得分: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表进行插入/更新/删除时,您将逐步支付该成本。
答案 3 :(得分: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
答案 4 :(得分: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