I am trying to clean up a WSUS DB, there are 2 stored procedures to help
exec spGetObsoleteUpdatesToCleanup
and
exec spDeleteUpdate @localUpdateID=xxxxxx
I'm trying to automate this a little so I wrote a little script to create a temp table, put the results from the first stored procedure in that then loop through the temp table running the second stored procedure against every entry...
The first part works, the second part doesn't appear to, anything glaringly obvious that I've done wrong...? Oh, and is it possable to make it have some sort of out put so I know how / what its doing...?
INSERT INTO #MyTempTable EXECUTE spGetObsoleteUpdatesToCleanup
SELECT * FROM #MyTempTable
GO
DECLARE @MyUpdateID int
DECLARE MyCur CURSOR FOR SELECT LocalUpdateID FROM #MyTempTable
OPEN MyCur
FETCH NEXT FROM MyCur INTO @MyUpdateID
WHILE @@FETCH_STATUS = 0 BEGIN
exec spDeleteUpdate @localUpdateID=@MyUpdateID
FETCH NEXT FROM MyCur INTO @MyUpdateID
END
CLOSE MyCur
DEALLOCATE MyCur
Just to be safe, let's make sure the cursor is a LOCAL one:
DECLARE @MyUpdateID int
DECLARE @ReturnCode int
DECLARE MyCur CURSOR LOCAL FAST_FORWARD FOR SELECT LocalUpdateID FROM #MyTempTable
OPEN MyCur
FETCH NEXT FROM MyCur INTO @MyUpdateID
WHILE @@FETCH_STATUS = 0 BEGIN
print 'EXECing proc spDeleteUpdate with id value = ' + CAST(@MyUpdateID AS varchar(10))
exec @ReturnCode = spDeleteUpdate @localUpdateID=@MyUpdateID
IF @ReturnCode <> 0 BEGIN
RAISERROR('Proc spDeleteUpdate got error %d when processing id %d.', 16, 1,
@ReturnCode, @MyUpdateID )
END /*IF*/
FETCH NEXT FROM MyCur INTO @MyUpdateID
END
CLOSE MyCur
DEALLOCATE MyCur
Thanks for your reply, yup looks good to me, seems to be working. One little glitch, the message that tells you which one is executing doesn't output until its finished, they all output at the same time. Any way to make it do a running comentary?
EDIT:
Cancel that, looks to be working fine, just a little slow to update. Thanks Scott.
You can use RAISERROR with a severity of 0 and the WITH NOWAIT option to help the output to the screen along instead of just using a PRINT or similar output.
If you are not familiar with CURORS and their vagaries I think it can often be better to just use a loop. It helps if you define the #TEMP table to have an IDENTITY column - lets call it [T_ID], but any Primary Key / Unique Column will do
DECLARE @T_ID int = 0, @RowCount int=1 -- Force first iteration
WHILE @RowCount >= 1
BEGIN
SELECT TOP 1 @T_ID = T_ID,
@MyUpdateID = LocalUpdateID
FROM #MyTempTable
WHERE T_ID > @T_ID
ORDER BY T_ID
SELECT @RowCount = @@ROWCOUNT
IF @RowCount = 1
BEGIN
exec @ReturnCode = spDeleteUpdate @localUpdateID=@MyUpdateID
IF @ReturnCode <> 0
BEGIN
... Error Handling Etc.
END
END
END
Cursor may perform faster in some situations, but not enough to make a difference for either small batches or one-of-jobs.
SQL is buffering the results, i.e., output is held until it reaches a certain size (fills the buffer), then SQL outputs it all at once. This is for efficiency. Afaik, the same occurs even if you specify RAISERROR WITH NOWAIT.
I get debug data appearing using RAISERROR WITH NOWAIT which does not appear (in a timely fashion) using PRINT, and thus use RAISERROR in that way for that purpose when PRINT is not outputting sooner enough.
But whether RAISERROR is "instant" or just "more sooner-ish" I don't know.
RAISERROR (and PRINT for that matter) can muck up APP code that is not expecting to get that "stuff" in the flow of packets from the server. We use an SProc @DEBUG parameter to turn on/off all debug messages