SELECT在游标中的位置不正确会导致弹出无数的表

时间:2015-10-19 14:07:28

标签: sql sql-server cursor temp-tables

我一直在忙着编写一个包含两个临时表和一个游标的存储过程。我收到这个作业已经两天了,这给了我一个艰难的时间,因为这是我第一次忙于编写这样的SP复杂性。

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

DATABASE_Y 中的 TableInfo 表包含 DATABASE_X 中的所有或大多数模式和表。类似的事情也适用于 ColumnInfo 表,唯一的区别是 TableInfo 表也能够包含列数据。

临时表分别包含 DATABASE_Y.TableInfo 中不存在的表的数据和 DATABASE_Y.ColumnInfo 中不存在的列的数据比较后填写。 (不存在意味着表A存在于DBX中但不存在于DBY.TableInfo的行中,反之亦然,对于列的情况而言)

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

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,而AAA的DBX上的第一个表是BBBBB      * AAA的第二个表是CCCCC;

我收到了无数数量的表,因为它看起来几乎不像是快速查询,只有AAA-BBBBB显示在5-6个表中,大约有5000行,然后转到AAA -CCCCC做了上面发生的事情,并且一直在继续。

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

我很高兴收到你们所有人对这个问题的建议。

我为单纯的文字墙道歉。

1 个答案:

答案 0 :(得分:1)

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

接下来就是为每个循环运行一次:

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

print @SchemaName + '-' + @TableName;

IF @@ROWCOUNT = 1
....

为了清晰起见,我添加了换行符和语句终止符,但第一个选择是为什么要获得大量结果集。这没有任何作用,将为数据库中的每一列运行。此外,如果你有IF @@ROWCOUNT = 1,它将始终返回0,因为它遵循打印命令,该命令不返回任何行。所以你永远不会进入" true"此IF/ELSE块的部分。

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

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);