我需要从数据库中清除一些数据。我编写了一个查询来搜索所有表中的特定GUID。
我拥有的数据库有大约400个表和2000个uniqueidentifier列。
运行查询后,我收到错误:
An error occurred while executing batch. Error message is: Exception of type 'System.OutOfMemoryException' was thrown.
我正在使用的查询:
DECLARE @begin INT = 1
, @end INT
, @table VARCHAR(250)
, @column VARCHAR(250)
, @sql NVARCHAR(MAX)
, @uniqueID nvarchar(100) = 'XXX'
SELECT @end = COUNT(COLUMN_NAME) from INFORMATION_SCHEMA.Columns INNER JOIN INFORMATION_SCHEMA.Tables ON INFORMATION_SCHEMA.Columns.TABLE_NAME = INFORMATION_SCHEMA.Tables.TABLE_NAME AND INFORMATION_SCHEMA.Tables.TABLE_TYPE = 'BASE TABLE' WHERE DATA_TYPE = 'uniqueidentifier'
WHILE @begin <= @end
BEGIN
;WITH ColumnID AS (
SELECT ROW_NUMBER() OVER (ORDER BY c.TABLE_NAME, c.COLUMN_NAME) AS ID
, c.TABLE_SCHEMA
, c.TABLE_NAME
, c.COLUMN_NAME
FROM INFORMATION_SCHEMA.Columns c
INNER JOIN INFORMATION_SCHEMA.Tables t ON c.TABLE_NAME = t.TABLE_NAME AND t.TABLE_TYPE = 'BASE TABLE'
WHERE DATA_TYPE = 'uniqueidentifier'
)
SELECT @table = TABLE_NAME, @column = COLUMN_NAME FROM ColumnID WHERE ID = @begin
SET @sql = 'SELECT ''' + @table + ''' AS ''Table Name'', ' + @column + ' AS ''Column Name'' FROM ' + @table + ' WHERE ' + @column + ' = ''' + @uniqueID + ''''
EXECUTE sp_executesql @sql
SET @begin = @begin + 1
END
问题1:
我该如何解决这个问题?
System.OutOfMemory错误是由于将过多的结果集返回给网格以供SSMS处理。这是客户端错误,而不是SQL Server。使用文件时一切正常(右键单击命令窗格,结果到 - &gt;文件)
问题2:
如何更改查询以获取一个包含表名和列名的表。
IF OBJECT_ID(N'tempdb..#_Results', 'U') IS NOT NULL DROP TABLE #_Results;
CREATE TABLE #_results (table_name sysname, column_name sysname)
DECLARE @begin INT = 1, @end INT, @table VARCHAR(250), @column VARCHAR(250), @sql NVARCHAR(MAX), @uniqueID nvarchar(100) = 'XXX'
SELECT @end = COUNT(COLUMN_NAME) from INFORMATION_SCHEMA.Columns INNER JOIN INFORMATION_SCHEMA.Tables ON INFORMATION_SCHEMA.Columns.TABLE_NAME = INFORMATION_SCHEMA.Tables.TABLE_NAME AND INFORMATION_SCHEMA.Tables.TABLE_TYPE = 'BASE TABLE' WHERE DATA_TYPE = 'uniqueidentifier'
WHILE @begin <= @end
BEGIN
;WITH ColumnID AS (
SELECT ROW_NUMBER() OVER (ORDER BY c.TABLE_NAME, c.COLUMN_NAME) AS ID
, c.TABLE_SCHEMA
, c.TABLE_NAME
, c.COLUMN_NAME
FROM INFORMATION_SCHEMA.Columns c
INNER JOIN INFORMATION_SCHEMA.Tables t ON c.TABLE_NAME = t.TABLE_NAME AND t.TABLE_TYPE = 'BASE TABLE'
WHERE DATA_TYPE = 'uniqueidentifier'
)
SELECT @table = TABLE_NAME, @column = COLUMN_NAME FROM ColumnID WHERE ID = @begin
SET @sql = 'INSERT INTO #_results SELECT DISTINCT ''' + @table + ''' AS TableName, ''' + @column + ''' AS ColumnName FROM [' + @table + '] WHERE [' + @column + '] = ''' + @uniqueID + '''' ;
EXECUTE sp_executesql @sql;
SET @begin = @begin + 1
END
SELECT * FROM #_results
DROP TABLE #_Results
答案 0 :(得分:2)
我不知道这会导致内存不足错误,但您的SQL是:
SET @sql = 'SELECT ''' + @table + ''' AS ''Table Name'', ' + @column + ' AS ''Column Name'' FROM ' + @table + ' WHERE ' + @column + ' = ''' + @uniqueID + ''''
尝试将其更改为:
SET @sql = 'SELECT DISTINCT ''' + @table + ''' AS TableName, ''' + @column + ''' AS ColumnName FROM [' + @table + '] WHERE [' + @column + '] = ''' + @uniqueID + '''' ;
这会做出以下更改:
如果这不起作用,请替换:
EXECUTE sp_executesql @sql;
使用:
SELECT @sql;
查看代码的哪一部分导致问题。
答案 1 :(得分:2)
这听起来像SSMS正在倒下,而不是服务器端。基本上,您向屏幕输出的结果太多,而Management Studio的可用资源不足以显示它们。
您最好的选择是将值写入临时表并使用单个最终SELECT语句。
这是我常用搜索脚本的修改副本供您试用。我在比较大的列集上的LIKE字符串比较上使用这个脚本而不是没有问题的攻击。</ p>
像这样的任何东西;这是一种资源匮乏。最好在测试/开发环境中运行它,不反对实时*
SET NOCOUNT ON;
DECLARE @value uniqueidentifier = '<put your guid here>'
, @sql varchar(4000)
;
IF Object_ID('tempdb..##results', 'U') IS NOT NULL
BEGIN
DROP TABLE ##results;
END
;
-- Temporary table to store SQL statements
CREATE TABLE ##results (
table_name sysname
, column_name sysname
, hit_count bigint
);
DECLARE e CURSOR FOR
SELECT 'INSERT INTO ##results (table_name, column_name, hit_count)'
+ Char(13) + 'SELECT ''' + table_schema + '.' + table_name + ''''
+ Char(13) + ' , ''' + column_name + ''''
+ Char(13) + ' , Count(*)'
+ Char(13) + 'FROM ' + QuoteName(table_schema) + '.' + Quotename(table_name)
+ Char(13) + 'WHERE ' + QuoteName(column_name) + ' = ' + QuoteName(@value, '''')
+ Char(13) + 'HAVING Count(*) > 0'
+ Char(13) + ';'
FROM information_schema.columns
WHERE data_type = 'uniqueidentifier'
;
-- Run SQL statements
OPEN e;
FETCH NEXT FROM e INTO @sql;
WHILE @@Fetch_Status = 0
BEGIN
EXEC (@sql);
FETCH NEXT FROM e INTO @sql;
END
;
CLOSE e;
DEALLOCATE e;
SET NOCOUNT OFF;
-- Display results
SELECT table_name
, column_name
, hit_count
FROM ##results
ORDER
BY table_name
, column_name
;
我想你会发现这对你更有效。
答案 2 :(得分:1)
这是我将使用的脚本:
DECLARE @sql NVARCHAR(MAX),
@TableName SYSNAME,
@ColumnName SYSNAME,
@uniqueID nvarchar(100) = 'XXX';
IF OBJECT_ID(N'tempdb..#Results', 'U') IS NOT NULL
DROP TABLE #Results;
CREATE TABLE #Results
(
TableName SYSNAME,
columnName SYSNAME
);
DECLARE TableCursor CURSOR STATIC LOCAL FORWARD_ONLY READ_ONLY
FOR
SELECT TableName = QUOTENAME(OBJECT_SCHEMA_NAME(c.object_id)) + '.' + QUOTENAME(OBJECT_NAME(c.object_id)),
ColumnName = QUOTENAME(c.name)
FROM sys.columns c
INNER JOIN sys.tables t
ON t.object_id = c.object_id
INNER JOIN sys.types ty
ON ty.system_type_id = c.system_type_id
AND ty.user_type_id = c.user_type_id
WHERE ty.Name = 'uniqueidentifier';
OPEN TableCursor;
FETCH NEXT FROM TableCursor INTO @TableName, @ColumnName;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = 'SELECT TOP 1 @Table, @Column FROM ' + @TableName + ' WHERE ' + @Columnname + ' = @UniqueID';
PRINT @SQL;
INSERT #Results (TableName, ColumnName)
EXECUTE sp_executesql @SQL, N'@Table SYSNAME, @Column SYSNAME, @uniqueID UNIQUEIDENTIFIER', @TableName, @ColumnName, @uniqueID;
FETCH NEXT FROM TableCursor INTO @TableName, @ColumnName;
END
CLOSE TableCursor;
DEALLOCATE TableCursor;
SELECT *
FROM #Results;
我已经用游标替换了while循环,因为它会表现得更好,并且我已经用对SQL Server特定系统视图的引用替换了对信息模式的引用,因为它们更可靠。
答案 3 :(得分:1)
对于第二个问题,要计算查询产生的行数,可以使用@@ rowcount,其中包含上次操作选择,删除,更新或插入的行数。
if(@@ rowcount&gt; 0)
select 'Good'
否则
select 'Nothing'