在 IF 语句和 WHILE 循环中执行 sp_executesql

Posted

技术标签:

【中文标题】在 IF 语句和 WHILE 循环中执行 sp_executesql【英文标题】:exec sp_executesql in an IF stament and WHILE loop 【发布时间】:2015-09-26 18:39:36 【问题描述】:

我的脚本有问题,它会搜索所有表名中包含“Dummy”的表。我有一个 SELECT 查询,结果将是要删除的表。

    SELECT  Row_Number() Over (Order By name) As RowNum
                        , name
                FROM    sys.all_objects
                WHERE   type = 'U'
                        and name like '%Dummy%'
                        and schema_id = @schemaID

它返回了:

    RowNum  name

    1   Dummy

    2   DummyJoinTbl1

    3   DummyJoinTbl2

    4   DummyJoinTbl3

但是当我执行下面的脚本时,

    DECLARE

    @schemaName nvarchar(100),
    @schemaID int,
    @tblName nvarchar(100) = '',
    @cnt int = 1,
    @rowNumber int = 1,
    @SQL nvarchar(100)

    SET @schemaName = (select SCHEMA_NAME()) -- this is dbo
    SET @schemaID = (select SCHEMA_ID()) -- this is 1

    BEGIN

    WHILE (@cnt > 0)
        BEGIN
            SELECT @tblName = +name
            FROM 
                (
                SELECT  Row_Number() Over (Order By name) As RowNum
                        , name
                FROM    sys.all_objects
                WHERE   type = 'U'
                        and name like '%Dummy%'
                        and schema_id = @schemaID
                ) ReferenceTable    
            WHERE RowNum = @rownumber

            SET @cnt = @@ROWCOUNT
            SET @rownumber = @rownumber + 1

            IF (@cnt > 0)
            BEGIN
                PRINT 'DROP TABLE ' + @schemaName + '.' + @tblName + ' - RowCount:' + cast(@cnt as nvarchar(100))
                set @SQL = 'DROP TABLE ' + @schemaName + '.' + @tblName
                exec sp_executesql @SQL

            END

        END

        PRINT 'DONE'

    END

它返回的结果:

    DROP TABLE dbo.Dummy - RowCount:1
    DROP TABLE dbo.DummyJoinTbl2 - RowCount:1
    DONE

错过其他表的原因可能是什么?当我删除时

    set @SQL = 'DROP TABLE ' + @schemaName + '.' + @tblName
        exec sp_executesql @SQL

它将打印所有表格。

    DROP TABLE dbo.Dummy - RowCount:1
    DROP TABLE dbo.DummyJoinTbl1 - RowCount:1
    DROP TABLE dbo.DummyJoinTbl2 - RowCount:1
    DROP TABLE dbo.DummyJoinTbl3 - RowCount:1
    DONE

请注意,给定的表格都是空的。提前致谢。

【问题讨论】:

set @SQL = 'DROP TABLE ' + @schemaName + '.' + @tblName改成SELECT @SQL = 'DROP TABLE ' + @schemaName + '.' + @tblName能用吗? 即使我使用 SELECT 而不是 SET 还是一样 如何将@SQL 设置为大于100 的长度?这似乎是一个截断问题。 并不是真正的截断问题,因为预期的字符少于 100。我确实尝试将 @SQL 的长度从 100 更改为 1000,但仍然相同。我认为这可能会涉及性能问题。我无权为此更改硬件或性能。我只能更改代码。 【参考方案1】:

这是使用光标的理想场所,如果您这样做,您需要的代码会少很多。这是一个简化的示例,它假设您只想从单个数据库中删除表:

USE TempDB1;

CREATE TABLE test1 (i INT);
CREATE TABLE test2 (i INT);
CREATE TABLE test3 (i INT);
CREATE TABLE test4 (i INT);

DECLARE @tableName VARCHAR(200),
    @sql NVARCHAR(MAX);

DECLARE c CURSOR FAST_FORWARD FOR
SELECT  name
FROM    sys.all_objects
WHERE   type = 'U'
        AND name LIKE '%test%'
        AND schema_id = SCHEMA_ID();

OPEN c;
FETCH NEXT FROM c INTO @tableName;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @sql = 'DROP TABLE ' + @tableName;
    PRINT @sql;
    EXEC sp_executesql @sql;

    FETCH NEXT FROM c INTO @tableName;
END;

CLOSE c;
DEALLOCATE c;

【讨论】:

我查看了代码,这似乎也有效。我选择了另一个,因为我想坚持我的代码。我从来没有测试过这个。感谢您的努力。 随心所欲,但这个版本更简单、更高效,因为它不需要多次运行 SELECT。【参考方案2】:

那是因为删除后select语句的第一个表结果变成了下一个:

1   DummyJoinTbl1

2   DummyJoinTbl2

3   DummyJoinTbl3

这是跳过DummyJoinTbl1的原因,因为@rownumber = 2. Next loop @rownumber = 3,它超过了记录数。 不要使用 WHERE RowNum = @rownumber

使用 SELECT TOP(1) @tblName = +name 没有嵌套选择和 ROW_NUMBER()

在 WHILE 语句中,最好使用带有 1 次选择的光标,而不是选择 N 次

【讨论】:

该死,那个打印让我很困惑哈哈。你的逻辑是正确的。欣赏努力。谢谢!

以上是关于在 IF 语句和 WHILE 循环中执行 sp_executesql的主要内容,如果未能解决你的问题,请参考以下文章

循环语句和条件语句

循环语句

初学python随笔——控制和循环语句

Python语法基础03(if语句,while循环与for循环)

c语言中的do while语句怎样理解

几种循环语句