I have a file system app that uses a SQL Server 2008 R2 to keep track of files. When I remove a file, I want to update parents in the path hierarchy to reflect their new size. I am using @fid for the current FILE_ID, @size as the FILE_SIZE, and @pid as the FILE_ID of the parent in the hierarchy.
Here is the loop I am using:
SELECT @pid=PARENT_ID FROM FILES WHERE FILE_ID=@fid;
WHILE @pid<>0
BEGIN
UPDATE FILES
SET
FILE_SIZE =
-- Avoid potential situation where new file size might incorrectly drop below 0
CASE
WHEN FILE_SIZE-@size>=0 THEN FILE_SIZE-@size
ELSE 0
END
WHERE FILE_ID=@pid;
SET @fid=@pid;
SELECT @pid=PARENT_ID FROM FILES WHERE FILE_ID=@fid;
END
When I run this, the sizes are not updating. If I replace the UPDATE with a SELECT, it looks like it should be working correctly. What is going on? Why are the sizes not getting updated? Is there a better way to do this?
To add some context, this snip-it is actually running inside another loop so multiple files can be deleted in a batch. Here is the code in this context:
-- Declarations
DECLARE @fid int, @size int, @pid int;
DECLARE c CURSOR FOR
SELECT
FILE_ID, FILE_SIZE
FROM
FILES
OPEN c;
-- Initialize variables
FETCH NEXT FROM c
INTO @fid, @size;
-- Main loop
WHILE @@FETCH_STATUS = 0
BEGIN
-- Statements to delete the file --
-- Loop to update sizes --
SELECT @pid=PARENT_ID FROM FILES WHERE FILE_ID=@fid;
WHILE @pid<>0
BEGIN
UPDATE FILES
SET
FILE_SIZE =
CASE
WHEN FILE_SIZE-@size>=0 THEN FILE_SIZE-@size
ELSE 0
END
WHERE FILE_ID=@pid;
SET @fid=@pid;
SELECT @pid=PARENT_ID FROM FILES WHERE FILE_ID=@fid;
END
FETCH NEXT FROM c
INTO @fid, @size;
END
CLOSE c;
DEALLOCATE c;
There is definately a better way to do this. The approach you outline is procedural and iterative and great for languages like C# and visual basic, however, for the most efficeint solution in SQL Cursors are the LAST trick you should reach for.
This should work
One command, no itteration – should be orders of magnitude quicker and you are getting the accurate filesizes propagated all the way up from the leaves each time.