Rob*_*ert 1 cursors sql-server-2012
我有以下脚本,该脚本在循环的第二次迭代中保持不变。
BEGIN
BEGIN TRY
BEGIN TRANSACTION
DECLARE @itemID int
DECLARE LoopCursor CURSOR FOR
SELECT DISTINCT i.ItemID
FROM Inventory i
INNER JOIN Items it ON i.ItemID = it.ItemID
WHERE i.ItemID IN (226, 231, 232, 233, 234, 235, 245, 247 ,249 ,250 ,253 ,254 ,255 ,257 ,258 ,268 ,270 ,271 ,273 ,286 ,287 ,291 ,293 ,299 ,303 ,304,
305, 306, 307, 308, 310, 311, 312, 313, 314, 316, 322, 323, 324, 331, 332, 333, 334, 335, 338, 339, 340, 341, 342, 343, 345, 346 ,347)
AND it.[Serializable] = 0
ORDER BY i.ItemID
OPEN LoopCursor
FETCH NEXT FROM LoopCursor
INTO @itemID
WHILE @@FETCH_STATUS = 0
--Drop Temp tables if they exist.
IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
IF OBJECT_ID('tempdb..#INV_TEMP') IS NOT NULL
DROP TABLE #INV_TEMP
BEGIN
DECLARE @inventoryID int = 0,
@quantity int = 0,
@statusID int = 10,
@maxInvID int
SET @inventoryID = (SELECT MAX(InventoryID) AS InventoryID FROM Inventory WHERE Inventory.ItemID = @itemID)
--Store Assets in temp table.
SELECT MAX(AssetID) AS AssetID, RoomID, COUNT(*) AS Quantity
INTO #TEMP
FROM Assets
WHERE InventoryID IN (SELECT InventoryID
FROM Inventory
WHERE ItemID = @itemID)
GROUP BY RoomID
--Update Assets with new Quantity value.
UPDATE Assets
SET Quantity = t.Quantity
FROM Assets a
INNER JOIN #TEMP t ON a.RoomID = t.RoomID
INNER JOIN Inventory i ON a.InventoryID = i.InventoryID
WHERE i.ItemID = @itemID
--Delete all other Assets with the same ItemID and that's not in the temp table.
DELETE a
FROM Assets a
INNER JOIN Inventory i ON a.InventoryID = i.InventoryID
INNER JOIN #TEMP t ON a.RoomID = t.RoomID
WHERE i.ItemID = @itemID
AND a.AssetID NOT IN (SELECT AssetID FROM #TEMP)
--Update Assets to have all the same InventoryID.
UPDATE Assets
SET Assets.InventoryID = @inventoryID, DateUpdated = GETDATE()
FROM Assets a
INNER JOIN Inventory i ON a.InventoryID = i.InventoryID
INNER JOIN #TEMP t ON a.RoomID = t.RoomID
WHERE i.ItemID = @itemID
AND a.AssetID IN (SELECT AssetID FROM #TEMP)
--Clean up Inventory now.
--Delete all Inventory with specific Statuses.
DELETE
FROM Inventory
WHERE ItemID = @itemID
AND StatusID IN (3, 6, 12, 14)
--Store Inventory records in a temp table
SELECT MAX(InventoryID) AS InventoryID, ItemID, StatusID, COUNT(*) AS Quantity
INTO #INV_TEMP
FROM Inventory
WHERE ItemID = @itemID
GROUP BY ItemID, StatusID
SELECT @maxInvID = MAX(InventoryID)
FROM #INV_TEMP
SELECT @quantity = t.Quantity
FROM #INV_TEMP t
WHERE StatusID = @statusID
--If there are no more of these items in inventory, change the status.
IF(@quantity = 0)
SET @statusID = 17
--Update the Quantity and Status for the given InventoryID and ItemID.
UPDATE Inventory
SET Quantity = @quantity,
StatusID = @statusID,
DateUpdated = GETDATE()
WHERE Inventory.InventoryID = @maxInvID
AND Inventory.ItemID = @itemID
--Delete all the other Inventory records with the same ItemID
DELETE
FROM Inventory
WHERE InventoryID <> @maxInvID
AND ItemID = @itemID
FETCH NEXT FROM LoopCursor
INTO @itemID
END
CLOSE LoopCursor
DEALLOCATE LoopCursor
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
DECLARE @ErrorNumber INT = ERROR_NUMBER();
DECLARE @ErrorLine INT = ERROR_LINE();
DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE();
DECLARE @ErrorSeverity INT = ERROR_SEVERITY();
DECLARE @ErrorState INT = ERROR_STATE();
PRINT 'Actual error number: ' + CAST(@ErrorNumber AS VARCHAR(10));
PRINT 'Actual line number: ' + CAST(@ErrorLine AS VARCHAR(10));
RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH
END
Run Code Online (Sandbox Code Playgroud)
我在游标方面不太擅长,但我需要做的是WHILE
块内的所有内容都需要基于 ItemID 运行。我可以将此脚本分成两个文件......一个仅更新资产,另一个仅更新库存表,每个文件都将按预期运行。当我把光标放在它挂起的整个东西周围的那一刻,它就出现了。
简而言之,我们有许多库存记录,它们具有相同的 ItemID,但具有不同的序列号。我们已经放弃了这一点,他们现在只想显示单个库存记录上给定 ItemID 的数量值。对于资产来说也是如此,只不过它们在 InventoryID 上与 Inventory 表连接。因此,由于已设置的关系,我必须首先更新资产部分,然后最后更新库存部分。
任何帮助是极大的赞赏。
仅从这段代码来看,就会发现“显然不好”的是,您启动了一个WHILE
循环,但在 之前有 2 个IF
语句BEGIN
:
WHILE @@FETCH_STATUS = 0
--Drop Temp tables if they exist.
IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
IF OBJECT_ID('tempdb..#INV_TEMP') IS NOT NULL
DROP TABLE #INV_TEMP
BEGIN
Run Code Online (Sandbox Code Playgroud)
其效果应该是只有下一个语句是 的一部分WHILE
,因此它会无限循环:
IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
Run Code Online (Sandbox Code Playgroud)
因为@@FETCH_STATUS
永远不会更新,因为FETCH
没有达到任何附加语句。
首先将 移至BEGIN
之前和之后:WHILE @@FETCH_STATUS = 0
IF
IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
Run Code Online (Sandbox Code Playgroud)
另外,为什么光标外面有BEGIN TRAN
/ ?这有效地使得所有单个操作的处理,而不仅仅是每个单个操作的语句。这是你真正想要的吗?或者您只是希望每个 individual及其所有操作成为原子操作,但仍与其他s 分开?如果希望它们分开(这似乎是更可能的情况),则将 移动到for的内部,并将 移动到循环末尾的之前。COMMIT
ItemID
@ItemID
@ItemID
ItemID
BEGIN TRAN
BEGIN
WHILE
COMMIT
FETCH NEXT FROM LoopCursor
归档时间: |
|
查看次数: |
7280 次 |
最近记录: |