In my DB I have two tables Items(Id, ..., ToatlViews int) and ItemViews (id, ItemId, Timestamp)
In ItemViews table I store all views of an item as they come to the site. From time to time I want to call a stored procedure to update Items.ToatlViews field. I tried to do this SP using a cursor ... but the update statement is wrong. Can you help me to correct it? Can I do this without cursor?
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
In such a case, you can use the following UPDATE statement syntax to update column from one table, based on value of another table. UPDATE first_table, second_table SET first_table. column1 = second_table. column2 WHERE first_table.id = second_table.
In this article, we will see, how to update from one table to another table based on ID match. We can update the table using UPDATE statement in SQL. The update statement is always followed by the SET command. The SET command is used to specify which columns and values need to be updated in a table.
UPDATE table SET col = new_value WHERE col = old_value AND other_col = some_other_value; UPDATE table SET col = new_value WHERE col = old_value OR other_col = some_other_value; As you can see, you can expand the WHERE clause as much as you'd like in order to filter down the rows for updating to what you need.
SELECT COUNT(*) FROM table_name; The COUNT(*) function will return the total number of items in that group including NULL values. The FROM clause in SQL specifies which table we want to list.
For who need to include zero count too
UPDATE Items as i,
(SELECT
i.Id as Id, COUNT(iv.ItemId) AS c
FROM
Items AS i
LEFT JOIN ItemViews AS iv ON i.Id = iv.ItemId
GROUP BY i.Id) AS ic
SET
i.TotalViews = ic.c
WHERE
i.Id = ic.Id
;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;
But why do you want to store this value, when you can always get the count at runtime? You're going to have to run this update statement every time you touch the ItemViews table in any way, otherwise the count stored with Items is going to be incorrect.
What you may consider doing instead is setting up an indexed view:
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);
Now you can join to the view in your queries and know that the count is always up to date (without paying the penalty of scanning for the count of each item). The downside to the indexed view is that you pay that cost incrementally when there are inserts/updates/deletes to the ItemViews table.
You could use update ... from
instead of a cursor:
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
You can use a direct UPDATE statement
update Items set TotalViews =
(select COUNT(id) from ItemViews where ItemViews.ItemId = Items.Id)
You might want to test performance for the various ways to do this, if that's important.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With