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);
我一直忙于编写包含两个临时 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);