0

BackDrop:我们正在研究为什么在一个过程中遗漏了许多帐户。我们已经回到我们有数据的地方。我们现在有一个相当大的帐户列表,无论出于何种原因,这些帐户都被遗漏了。现在这个过程没有过多的细节是非常非常复杂的,我们需要知道为什么这些账户并且只有这些账户被遗漏了。与任何数据库一样,我们有许多一直在运行的自动化程序,所以在这一点上真的不知道到底发生了什么导致这些帐户被遗漏。我认为解决这个问题的唯一办法是找到这些帐户之间的相似之处。显然,我们已经尝试查看更常见的地方,但此后一无所获。

问题:我想使用 SQL 返回我们数据库中的所有表名和列名,其中这些帐户列表在表的一列或多列中具有相同的值。我创建了一个查询来查找表名、列等,但不知道如何将它们组合在一起以创建一个查询,该查询将为我提供我想要的所有结果。我确信需要使用游标并进行大量内部连接,但我只是不确定应该如何完成。
再说一遍:假设我有帐号 123456 和 654321,并且我知道我们的数据库有 3,000 个表,其中列引用了帐号,名称为 AccountNumber、AccountNum 或 Account。我想搜索并查找具有名称为 AccountNumber、AccountNum 或 Account 的列的所有表,其值为 123456 或 654321。然后对于这些表,对于每个表,我要获取行 Where 列是否名称是 AccountNumber、AccountNum 或 Account 的值是 123456 和 654321,然后对于这些行中的每一行,我想检查每一行的每一列,以查看帐号 123456 的行上的列是否等于 a 上的列帐号 654321 的行,如果是,那么我希望它返回列名和表名。通过这种方式,我可以看到这些帐户的共同点。

高级部分:

如果某个可怜的灵魂能够做到以上几点,那么我还想创建一个查询,该查询将返回表名及其更新时间。我将通过检查每个表中的每一列来获得更新的值,如果该列具有“时间戳”类型或“GetDate()”的默认值,那么该列将被用作更新。在最终结果集中,显示所有更改都发生在那些将按更新排序的帐户编号上。

4

2 回答 2

0

第一种方法,质朴的(我不习惯 T-SQL,我做了更多的 PL/SQL),但这可能会帮助你走得更远,并在 SQL SERVER 2008 中测试。希望它在 2005 年有效......)

所以,我们创建了两个过程,一个调用另一个

提供的代码只能一次检查 - 2 个不同的 ID - 所有相关字段(Account、AccountNum、AccountNumber)

这个想法(检查 AccountNumber 列)

查找表(在表 INFORMATION_SCHEMA.columns 中,其中列出了您的数据库表),其中的列具有提供的 3 个名称之一

对于找到的每个表:创建一个动态查询:

select count(*) from <THE_TABLE> where <Account_column_name> IN (123456 654321);

如果我们有 2 个结果(意味着我们的 Id 都存在于表中),我们启动第二个过程,参数为 : @TableName = <THE_TABLE>, @FieldName = <Account_column_name>, @FirstId = 123456,@SecondId = 654321

<THE_TABLE>我们找到了(同样在 INFORMATION_SCHEMA.columns 中)的列名。对于找到的每一列:创建一个动态查询

select count(*) from <THE_TABLE> as T1
inner join <THE_TABLE> as T2 on T1.<COLUMN_NAME> = T2.<COLUMN_NAME>
where T1.<Account_column_name>= 123456
and T2.<Account_column_name>= 654321

如果count(*) = 1,则表示对于给定的 id,相同的值存在于同一张表的同一列中。

在这种情况下,我们打印<THE_TABLE><THE_COLUMN>

要启动搜索,在 sql management studio 中,只需

EXEC GetSimilarValuesForFieldAndValue  123456, 654321

在“消息”部分,您应该有一个“结果”列表。

CREATE procedure [dbo].[GetSimilarValuesForFieldAndValue](@FirstId int, @SecondId int)
AS


DECLARE @sql nvarchar(MAX);
DECLARE @params NVARCHAR(MAX);
DECLARE @Count int;
DECLARE @Name NVARCHAR(MAX);
DECLARE @FieldName NVARCHAR(MAX);

DECLARE db_cursor CURSOR for
select TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.columns
where COLUMN_NAME IN('Account', 'AccountNumber', 'AccountNum');



OPEN db_cursor
FETCH next from db_cursor into @Name, @FieldName
while @@FETCH_STATUS = 0
 begin
     select @sql = 
     N' SELECT @Count=Count(*) FROM ' + @Name +
     N' WHERE ' +@FieldName+' IN (@FirstId,@SecondId)'
     SELECT @params = N'@FieldName NVARCHAR(MAX), @FirstId int, @SecondId int, @Count int out'
     EXEC sp_executesql @sql, @params, @FieldName, @FirstId, @SecondId, @Count OUT
     if (@Count = 2)
     begin
      exec dbo.CompareFields @Name, @FieldName, @FirstId, @SecondId
     end
     FETCH NEXT FROM db_cursor INTO @Name, @FieldName    
 end
 close db_cursor
 DEALLOCATE db_cursor
GO

第二个 :

CREATE procedure [dbo].[CompareFields](@TableName NVARCHAR(MAX), @FieldName NVARCHAR(MAX), @FirstId int, @SecondId int)  
as


DECLARE @ColumnName NVARCHAR(MAX)
DECLARE @Sql NVARCHAR(MAX)
DECLARE @Params NVARCHAR(MAX)
DECLARE @Count int


DECLARE cfCursor CURSOR FOR
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = ''+@TableName+' '
AND COLUMN_NAME <> ' '+@FieldName+''




OPEN cfCursor
  FETCH next from cfCursor into @ColumnName
  while @@FETCH_STATUS = 0

    begin
    select @Sql = 
    N' SELECT @Count = count(*) from ' +@TableName + ' T1 '+
    N' INNER JOIN ' + @TableName + ' T2 ON T1.' +@ColumnName + ' = T2.' + @ColumnName +
    N' WHERE T1.' +@FieldName + ' = '+ CAST(@FirstId as varchar) +
    N' AND T2.' + @FieldName + ' = '+CAST(@SecondId as varchar)
    SELECT @Params = 
    N'@TableName VARCHAR(MAX), @ColumnName VARCHAR(MAX), '+
    N'@FieldName VARCHAR(MAX), @FirstId int, @SecondId int, @Count int out'
    exec sp_executesql  @sql, @Params, @TableName, @ColumnName, @FieldName, @FirstId, @SecondId, @Count OUT
    if @Count = 1
    begin
    --print tableName and column Name if value is identic
     print 'Table : ' + @TableName + ' : same value for ' + @ColumnName
    end
    FETCH NEXT FROM cfCursor INTO @ColumnName    
    end
 close cfCursor

 DEALLOCATE cfCursor
GO
于 2012-05-11T10:34:29.887 回答
0

实际上,我曾经一度不得不为 Guids 做这件事。这是使用 Guids 的脚本。一秒钟,我将根据您的需要对其进行修改:

DECLARE @table VARCHAR(100)
DECLARE @column VARCHAR(100)
DECLARE @value INT

SET @value = '06B8BD6C-A8EC-4EB3-9562-6666EE86952D'

DECLARE table_cursor CURSOR
FOR select tbl.Name, cols.name as TableName  FROM sys.columns cols  JOIN 
    sys.tables tbl on cols.object_id = tbl.object_id
    where system_type_id = 36

OPEN table_cursor 
FETCH NEXT FROM table_cursor 
INTO @table, @column;

WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @SQL NVARCHAR(1000)

SET @SQL = 'SELECT ''' + @Table + '''  AS TBL,''' + 
@column + ''' AS COL FROM [' + @table + '] 
WITH(NOLOCK) WHERE ' + @column + ' = ''' + CAST(@value AS VARCHAR(50)) + ''''

    print @sql
EXEC sp_executesql @Sql

FETCH NEXT FROM table_cursor 
INTO @table, @column;

END

CLOSE table_cursor
DEALLOCATE table_cursor

更新以处理搜索字段名称:

DECLARE @table VARCHAR(100)
DECLARE @column VARCHAR(100)
DECLARE @value UNIQUEIDENTIFIER

SET @value = --ENTER YOUR ACCOUNT NUMBER HERE

DECLARE table_cursor CURSOR

select tbl.Name, cols.name as TableName  FROM sys.columns cols  JOIN 
    sys.tables tbl on cols.object_id = tbl.object_id
    where cols.Name = 'AccountNumber' 
    OR cols.Name = 'AccountNum' OR cols.Name = 'Account'

OPEN table_cursor 
FETCH NEXT FROM table_cursor 
INTO @table, @column;

WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @SQL NVARCHAR(1000)

SET @SQL = 'SELECT ''' + @Table + '''  AS TBL,''' + @column + 
    ''' AS COL FROM [' + @table + '] WITH(NOLOCK) 
WHERE ' + @column + ' = ''' + CAST(@value AS VARCHAR(50)) + ''''
    print @sql
    EXEC sp_executesql @Sql

FETCH NEXT FROM table_cursor 
INTO @table, @column;

END

CLOSE table_cursor
DEALLOCATE table_cursor
于 2012-05-11T14:14:07.503 回答