DI 编写了一个游标来迭代表的行。我的要求是我不想检查所有列的状况。如果我的条件与第 1 列匹配,则不检查其他列的条件并将光标移动到下一行。如果条件与第 1 列不匹配,则检查第 2 列,依此类推。我尝试过使用 Break 和 continue 这两个关键字,但没有一个按照我的要求工作。下面是我的光标。
Declare @InputResourceId int,@ResourceTypeId int,@CoreAppId int,@SiteId int,@CompetencyID int,@EstaffId int,
@CostCenterId int, @PVLocationId int,@EngineeringCostId int, @CostCategoryId int, @ExpenseTypeId int
Declare InputResourceCursor CURSOR FOR
SELECT InputResourceId, ResourceTypeId,CoreAppId, SiteId, CompetencyId, EStaffId, CostCenterId, PVLocationId
from InputResource where EFITID = 214
OPEN InputResourceCursor
FETCH NEXT FROM InputResourceCursor INTO @InputResourceId,@ResourceTypeId,@CoreAppId,@SiteId,@CompetencyID,@EstaffId,@CostCenterId,@PVLocationId
WHILE (@@FETCH_STATUS = 0)
BEGIN
Declare @Status1 int
SET @Status1 = (Select Status from tblResourceType where ResourceTypeId = @ResourceTypeId)
IF(@Status1 = 0)
BEGIN
UPDATE InputResource SET Status = 2 where InputResourceId = @InputResourceId
-- Here I want to move my cursor to the next row. If I put my Fetch next here then also its not working properly.
END
SET @Status1 = (Select Status from tblCoreApp where CoreAppId = @CoreAppId)
IF(@Status1 = 0)
BEGIN
UPDATE InputResource SET Status = 2 where InputResourceId = @InputResourceId
END
SET @Status1 = (Select Status from tblSiteMaster where SiteId = @SiteId)
IF(@Status1 = 0)
BEGIN
UPDATE InputResource SET Status = 2 where InputResourceId = @InputResourceId
END
SET @Status1 = (Select Status from tblCompetency where CompetencyId = @CompetencyID)
IF(@Status1 = 0)
BEGIN
UPDATE InputResource SET Status = 2 where InputResourceId = @InputResourceId
END
SET @Status1 = (Select Status from Estaff where EStaffId = @EstaffId)
IF(@Status1 = 0)
BEGIN
UPDATE InputResource SET Status = 2 where InputResourceId = @InputResourceId
END
SET @Status1 = (Select Status from CostCenter where CostCenterId = @CostCenterId)
IF(@Status1 = 0)
BEGIN
UPDATE InputResource SET Status = 2 where InputResourceId = @InputResourceId
END
SET @Status1 = (Select Status from PlanViewLocationMaster where PlanviewLocationID = @PVLocationId)
IF(@Status1 = 0)
BEGIN
UPDATE InputResource SET Status = 2 where InputResourceId = @InputResourceId
END
FETCH NEXT FROM InputResourceCursor INTO @InputResourceId,@ResourceTypeId,@CoreAppId,@SiteId,@CompetencyID,@EstaffId,@CostCenterId,@PVLocationId
END
CLOSE InputResourceCursor
DEALLOCATE InputResourceCursor
我相信您可以在单个
EXISTS(SELECT TOP 1 * FROM (select1 UNION select2 UNION ...) U)
条件内移动所有状态选择,其中每个 selectN
的形式为 Select Status from ... where ... and Status = 0
。我希望 TOP 1 应该快捷方式 UNION ALL,这样一旦找到满足其条件的选择,其余的选择将被跳过。
这种方法可以封装成一个集合操作,从而消除游标循环。
UPDATE I
SET Status = 2
FROM InputResource I
WHERE I.EFITID = 214
AND EXISTS (
SELECT TOP 1 *
FROM (
Select Status from tblResourceType where ResourceTypeId = @ResourceTypeId And Status = 0
UNION ALL
Select Status from tblCoreApp where CoreAppId = @CoreAppId AND Status = 0
UNION ALL
Select Status from tblSiteMaster where SiteId = @SiteId AND Status = 0
UNION ALL
Select Status from tblCompetency where CompetencyId = @CompetencyID AND Status = 0
UNION ALL
Select Status from Estaff where EStaffId = @EstaffId AND Status = 0
UNION ALL
Select Status from CostCenter where CostCenterId = @CostCenterId AND Status = 0
UNION ALL
Select Status from PlanViewLocationMaster where PlanviewLocationID = @PVLocationId AND Status = 0
) U
)
可能不需要
SELECT TOP 1 *
级别,因为我预计EXISTS(...)
测试也会快捷。这将简化查询,如下所示。
UPDATE I
SET Status = 2
FROM InputResource I
WHERE I.EFITID = 214
AND EXISTS (
Select ...
)
另一个等效的替代方法是使用
CROSS APPLY
代替 EXISTS()
。 CROSS APPLY 就像子选择的内部联接。如果没有匹配到内层行,则丢弃外层行。
UPDATE I
SET Status = 2
FROM InputResource I
CROSS APPLY (
SELECT TOP 1 *
FROM (
Select ...
) U
) C
WHERE I.EFITID = 214
无论如何,我都会鼓励进行测试,以确保结果具有预期的性能,并且快捷逻辑已到位,以避免不必要的子查询执行。 (如果您设置第一个或第二个子选择全部匹配的场景,则执行计划应显示其他选择访问的零行。)
最后,仔细检查这些子查询中引用的表是否有适当的索引。大多数看起来像 PK 查找,所以你可能很好。