带有T-SQL的无限WHILE循环

时间:2016-08-21 09:42:03

标签: sql-server tsql

我有以下while循环,它永远不会停止。它永远打印8结束。谁能告诉我为什么?

DECLARE @catID int

SELECT TOP(1)
    @catID = categoryid 
FROM 
    [Production].[Categories] 
ORDER BY 
    categoryid

WHILE @catID IS NOT NULL
BEGIN
    PRINT @catID    --do something

    SELECT TOP(1) 
        @catID = categoryid 
    FROM 
        [Production].[Categories] 
    WHERE 
        categoryid > @catID
    ORDER BY 
        categoryid
END

4 个答案:

答案 0 :(得分:4)

以下是您的代码的逻辑问题:

  • @catID成为NULL
  • 时,循环中断
  • 这将要求查询中的第一条记录@catIDNULL
  • 反过来要求该记录的WHERE子句为TRUE,并返回记录
  • 但是,如果@catIDNULL,则WHERE条件永远不会成立:WHERE categoryid > @catID


这样做的原因是,使用不等式将cateogoryidNULL值进行比较将始终返回NULL(未知),而不是真或假。

如何解决此问题:

您可以尝试在WHERE子句中添加一个额外的检查,以允许返回NULL分解记录:

WHILE @catID IS NOT NULL
BEGIN
    PRINT @catID

    SELECT TOP(1) 
        @catID = categoryid 
    FROM 
        [Production].[Categories] 
    WHERE 
        categoryid > @catID OR @catID IS NULL
    ORDER BY 
        categoryid
END

答案 1 :(得分:2)

在重新选择之前,您需要重新初始化变量@catIDNULL - 因为如果没有任何内容可供选择,则不会返回任何行和之前的值将保留在@catID中(因此,它永远不会设置为NULL并且永远不会满足IS NOT NULL条件。)

试试这个:

WHILE @catID IS NOT NULL
BEGIN
    PRINT @catID    --do something

    SET @catID = NULL   -- re-initilatize to NULL

    SELECT TOP(1) 
        @catID = categoryid 
    FROM 
        [Production].[Categories] 
    WHERE 
        categoryid > @catID
    ORDER BY 
        categoryid
END

答案 2 :(得分:2)

您的问题必须是,DI语句在某些时候找不到任何价值,并且不会为您的BP变量分配任何新内容,并且与SELECT变量完全相同它在之前的循环中。结果 - 你永远不会退出你的while语句。

代码段解释:

@catID

结果:

DECLARE @catID INT = 5;

DECLARE @Test TABLE
(
    CategoryID INT
);

/**
 * Notice that I do not insert into table intentionally,
 * so that following query doesn't assign anything
 * to @catID variable
 */

SELECT TOP (1) @catID = CategoryID
FROM @Test;

SELECT @catID AS [@catID];

此查询返回5,而不是您期望的@catID ----------- 5

使用子查询分配值将分配实际值,如果找不到任何内容,则分配NULL,这意味着当没有类别高于NULL时,它将变为{{1你的查询将转义循环。

@catID

答案 3 :(得分:0)

至于为何 这将每次返回零行 你已经有了top,所以没有categoryid> @catID

@catID未赋值null 它根本没有分配

   SELECT TOP(1) 
        @catID = categoryid 
    FROM 
        [Production].[Categories] 
    WHERE 
        categoryid > @catID
    ORDER BY 
        categoryid

修复

DECLARE @catID int 
DECLARE @count int = 1 

SELECT TOP(1)
    @catID = categoryid 
FROM 
    [Production].[Categories] 
ORDER BY 
    categoryid

WHILE @count > 0
BEGIN
    PRINT @catID    --do something

    SELECT TOP(1) 
        @catID = categoryid 
    FROM 
        [Production].[Categories] 
    WHERE 
        categoryid > @catID
    ORDER BY 
        categoryid

    Select @count = select count(*) FROM [Production].[Categories] 
    WHERE categoryid > @catID
END

但是你的逻辑有更多问题。获得前1后你就拥有它。没有更多的前1名。

DECLARE @catID int
DECLARE @catIDnew int

SELECT TOP(1)
    @catID = categoryid 
FROM 
    [Production].[Categories] 
ORDER BY 
    categoryid

WHILE @catID IS NOT NULL
BEGIN
    PRINT @catID    --do something

    @catIDnew = null

    SELECT TOP(1) 
        @catIDnew = categoryid 
    FROM 
        [Production].[Categories] 
    WHERE 
        categoryid > @catID
    ORDER BY 
        categoryid

    @catID =@catIDnew

END