SELECT 在游标中的错误放置会导致弹出无数表格

Incorrect placement of SELECT in a cursor causes countless amount of tables pop up

我一直忙于编写包含两个临时 table 和一个游标的存储过程。接到这个任务已经两天了,这让我很辛苦,因为这是我第一次忙于编写如此复杂的SP。

游标应该从 DATABASE_X 派生数据,并允许获取该数据以与 DATABASE_Y 进行比较。

TableInfo table in DATABASE_Y 是为了包含所有或者大部分的模式和table 位于 DATABASE_X 中。 ColumnInfo table 也有类似的情况,唯一的区别是 TableInfo table 能够也包含列数据。

临时tables,分别包含DATABASE_Y.TableInfo中不存在的tables和不存在的tables的数据DATABASE_Y.ColumnInfo 中的现有列将在比较后填充。 (不存在表示 table A 存在于 DBX 但不存在于 DBY.TableInfo 的行中,对于列的情况反之亦然)

DATABASE_Y.TableInfo 中存在的 NotInUse 列是决定是否应考虑检查 DBX 中的 table 的决定因素。

CREATE TABLE #NONEXISTENT_TABLES(
    SCHEMA_NAME VARCHAR(100),
    TABLE_NAME VARCHAR(100)
)

CREATE TABLE #NONEXISTENT_COLUMNS(
    SCHEMA_NAME VARCHAR(100),
    TABLE_NAME VARCHAR(100),
    COLUMN_NAME VARCHAR(100)
)

DECLARE @SchemaName VARCHAR(100)
DECLARE @TableName VARCHAR(100)
DECLARE @ColumnName VARCHAR(100)

USE DATABASE_X;
DECLARE CRS_GET_NONEXISTENT_STUFF CURSOR FOR
        select s.name as 'sname', t.name as 'tname', c.name as 'cname'
        from sys.schemas (nolock) s
        join sys.tables (nolock) t 
            on s.schema_id = t.schema_id
        join sys.columns (nolock) c 
            on c.object_id = t.object_id
        order by 1,2,3
OPEN CRS_GET_NONEXISTENT_STUFF

FETCH NEXT FROM CRS_GET_NONEXISTENT_STUFF INTO @SchemaName,
                                                 @TableName,
                                                 @ColumnName

WHILE @@FETCH_STATUS = 0
BEGIN
    select @SchemaName, @TableName
    from DATABASE_Y..TableInfo (nolock) ti
    print @SchemaName + '-' + @TableName
    IF @@ROWCOUNT = 1
    BEGIN
        declare @NotInUse varchar(100)
        select @NotInUse = ti.[NotInUse]
        from DATABASE_Y..TableInfo (nolock) ti
        where ti.[Schema] = @SchemaName
        and ti.[Name] = @TableName
        print @SchemaName + '-' + @TableName
        IF @NotInUse = '0'
        DECLARE @colname varchar(100)
        BEGIN
            select @colname = ci.[Name]
            from DATABASE_Y..ColumnInfo (nolock) ci
            where ci.[TableSchema] = @SchemaName
            and ci.[TableName] = @TableName
            and ci.[Name] = @ColumnName
            print @SchemaName + '-' + @TableName + '-' + @ColumnName
            IF @colname IS NULL
            BEGIN
                INSERT INTO #NONEXISTENT_COLUMNS(SEMA_ADI, TABLO_ADI, KOLON_ADI)
                VALUES(@SchemaName, @TableName, @colname)
            END
        END
    END
    ELSE
        INSERT INTO #NONEXISTENT_TABLES(SCHEMA_NAME, TABLE_NAME)
        VALUES (@SchemaName, @TableName)
    FETCH NEXT FROM CRS_GET_NONEXISTENT_STUFF INTO @SchemaName,
                                                 @TableName,
                                                 @ColumnName
END

CLOSE CRS_GET_NONEXISTENT_STUFF
DEALLOCATE CRS_GET_NONEXISTENT_STUFF

SELECT * FROM #NONEXISTENT_COLUMNS

SELECT * FROM #NONEXISTENT_TABLES


DROP TABLE #NONEXISTENT_COLUMNS


DROP TABLE #NONEXISTENT_TABLES

假设: *DBX 上的第一个架构是 AAA,DBX 上 AAA 的第一个 table 是 BBBBB *AAA第二个table是CCCCC;

我收到了无数的 table 作为一个看起来很难很快结束的查询的结果,在 5-6 [=57] 中只显示 AAA-BBBBB =]s 有大约 5000 行,然后移动到 AAA-CCCCC 执行上面发生的事情,它继续下去。

我认为我的错误是将 SELECT 命令放在 WHILE 循环下,但我也相信这不是我唯一的错误...

如果能就此问题向大家提出建议,我将不胜感激。

对于文字墙,我深表歉意。

我建议的第一件事是阅读这篇文章 - Bad habits : Putting NOLOCK everywhere

接下来的事情是,对于每个循环,你 运行 这个:

select @SchemaName, @TableName
from DATABASE_Y..TableInfo (nolock) ti;

print @SchemaName + '-' + @TableName;

IF @@ROWCOUNT = 1
....

为了清楚起见,我添加了换行符和语句终止符,但第一个 select 是您获得大量结果集的原因。这什么都不做,并且将 运行 用于数据库中的每一列。此外,在您有 IF @@ROWCOUNT = 1 的地方,它总是 return 0,因为它遵循打印命令,return 没有行。所以你永远不会进入这个 IF/ELSE 块的 "true" 部分。

我很确定您根本不需要游标,并且作为一般规则,除非您绝对必须使用游标,否则您不应该使用游标。所以我认为您可以简单地用两个基于集合的插入替换所有循环:

CREATE TABLE #NONEXISTENT_TABLES(
    SCHEMA_NAME VARCHAR(100),
    TABLE_NAME VARCHAR(100),
    object_id INT NOT NULL
);

CREATE TABLE #NONEXISTENT_COLUMNS(
    SCHEMA_NAME VARCHAR(100),
    TABLE_NAME VARCHAR(100),
    COLUMN_NAME VARCHAR(100)
);

INSERT #NONEXISTENT_TABLES (SCHEMA_NAME, TABLE_NAME, objecobject_idt_ID)
SELECT  s.name, t.Name, object_id
FROM    sys.tables AS t
        INNER JOIN sys.schemas AS s
            ON s.schema_id = t.schema_id
WHERE   NOT EXISTS
        (   SELECT  1
            FROM    DATABASE_Y..TableInfo AS ti
            WHERE   ti.TableSchema = s.Name
            AND     ti.name = t.name
            --AND       ti.NotInUse = 0
        );

INSERT #NONEXISTENT_COLUMNS (SCHEMA_NAME, TABLE_NAME, COLUMN_NAME)      
SELECT  nt.SCHEMA_NAME, nt.TABLE_NAME, c.name
FROM    sys.columns AS c
        INNER JOIN #NONEXISTENT_TABLES AS nt 
            ON nt.object_id = c.object_id);