[sql] DB의 모든 테이블, 행 및 열에서 문자열 검색

나는 큰 데이터베이스에서 길을 잃었고 내가 얻은 데이터의 출처를 찾을 수 없습니다. SQL Server 2005에서 데이터베이스의 모든 테이블, 행 및 열에서 문자열을 검색 할 수 있는지 궁금합니다.

가능한 경우 아이디어가있는 사람이 있습니까?



답변

이 코드는 SQL 2005에서이를 수행해야하지만 몇 가지주의 사항이 있습니다.

  1. 엄청나게 느립니다. 몇 개의 테이블 만 가지고있는 작은 데이터베이스에서 테스트했으며 완료하는 데 몇 분이 걸렸습니다. 데이터베이스가 너무 커서 이해할 수 없다면 어쨌든 사용할 수 없을 것입니다.

  2. 나는 이것을 팔목에 썼다. 나는 오류 처리를하지 않았고 특히 커서를 자주 사용하지 않기 때문에 다른 엉성한 부분이있을 수 있습니다. 예를 들어, 열 커서를 매번 닫거나 할당 해제 / 다시 만드는 대신 열 커서를 새로 고치는 방법이 있다고 생각합니다.

데이터베이스를 이해하지 못하거나 자료가 어디에서 오는지 모른다면 아마 이해하는 사람을 찾아야합니다. 데이터가있는 위치를 찾을 수 있더라도 어딘가에 중복되거나 이해하지 못하는 데이터베이스의 다른 측면이있을 수 있습니다. 회사의 아무도 데이터베이스를 이해하지 못한다면 꽤 엉망인 것입니다.

DECLARE
    @search_string  VARCHAR(100),
    @table_name     SYSNAME,
    @table_schema   SYSNAME,
    @column_name    SYSNAME,
    @sql_string     VARCHAR(2000)

SET @search_string = 'Test'

DECLARE tables_cur CURSOR FOR SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'

OPEN tables_cur

FETCH NEXT FROM tables_cur INTO @table_schema, @table_name

WHILE (@@FETCH_STATUS = 0)
BEGIN
    DECLARE columns_cur CURSOR FOR SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @table_schema AND TABLE_NAME = @table_name AND COLLATION_NAME IS NOT NULL  -- Only strings have this and they always have it

    OPEN columns_cur

    FETCH NEXT FROM columns_cur INTO @column_name
    WHILE (@@FETCH_STATUS = 0)
    BEGIN
        SET @sql_string = 'IF EXISTS (SELECT * FROM ' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ' WHERE ' + QUOTENAME(@column_name) + ' LIKE ''%' + @search_string + '%'') PRINT ''' + QUOTENAME(@table_schema) + '.' + QUOTENAME(@table_name) + ', ' + QUOTENAME(@column_name) + ''''

        EXECUTE(@sql_string)

        FETCH NEXT FROM columns_cur INTO @column_name
    END

    CLOSE columns_cur

    DEALLOCATE columns_cur

    FETCH NEXT FROM tables_cur INTO @table_schema, @table_name
END

CLOSE tables_cur

DEALLOCATE tables_cur


답변

ApexSQL Search 와 같은 타사 도구를 사용하는 것이 좋습니다 (아마도 다른 도구 도있을 수 있지만 무료이기 때문에이 도구를 사용합니다).

정말로 SQL 방식으로 가고 싶다면 Sorna Kumar Muthuraj가 만든 저장 프로 시저를 사용해 볼 수
있습니다. 복사 된 코드는 다음과 같습니다. 스키마의 모든 테이블에 대해이 저장 프로 시저를 실행하기 만하면됩니다 (동적 SQL 사용이 쉬움).

CREATE PROCEDURE SearchTables
 @Tablenames VARCHAR(500)
,@SearchStr NVARCHAR(60)
,@GenerateSQLOnly Bit = 0
AS

/*
    Parameters and usage

    @Tablenames        -- Provide a single table name or multiple table name with comma seperated.
                        If left blank , it will check for all the tables in the database
    @SearchStr        -- Provide the search string. Use the '%' to coin the search.
                        EX : X%--- will give data staring with X
                             %X--- will give data ending with X
                             %X%--- will give data containig  X
    @GenerateSQLOnly -- Provide 1 if you only want to generate the SQL statements without seraching the database.
                        By default it is 0 and it will search.

    Samples :

    1. To search data in a table

        EXEC SearchTables @Tablenames = 'T1'
                         ,@SearchStr  = '%TEST%'

        The above sample searches in table T1 with string containing TEST.

    2. To search in a multiple table

        EXEC SearchTables @Tablenames = 'T2'
                         ,@SearchStr  = '%TEST%'

        The above sample searches in tables T1 & T2 with string containing TEST.

    3. To search in a all table

        EXEC SearchTables @Tablenames = '%'
                         ,@SearchStr  = '%TEST%'

        The above sample searches in all table with string containing TEST.

    4. Generate the SQL for the Select statements

        EXEC SearchTables @Tablenames        = 'T1'
                         ,@SearchStr        = '%TEST%'
                         ,@GenerateSQLOnly    = 1

*/

    SET NOCOUNT ON

    DECLARE @CheckTableNames Table
    (
    Tablename sysname
    )

    DECLARE @SQLTbl TABLE
    (
     Tablename        SYSNAME
    ,WHEREClause    VARCHAR(MAX)
    ,SQLStatement   VARCHAR(MAX)
    ,Execstatus        BIT
    )

    DECLARE @sql VARCHAR(MAX)
    DECLARE @tmpTblname sysname

    IF LTRIM(RTRIM(@Tablenames)) IN ('' ,'%')
    BEGIN

        INSERT INTO @CheckTableNames
        SELECT Name
          FROM sys.tables
    END
    ELSE
    BEGIN

        SELECT @sql = 'SELECT ''' + REPLACE(@Tablenames,',',''' UNION SELECT ''') + ''''

        INSERT INTO @CheckTableNames
        EXEC(@sql)

    END

    INSERT INTO @SQLTbl
    ( Tablename,WHEREClause)
    SELECT SCh.name + '.' + ST.NAME,
            (
                SELECT '[' + SC.name + ']' + ' LIKE ''' + @SearchStr + ''' OR ' + CHAR(10)
                  FROM SYS.columns SC
                  JOIN SYS.types STy
                    ON STy.system_type_id = SC.system_type_id
                   AND STy.user_type_id =SC.user_type_id
                 WHERE STY.name in ('varchar','char','nvarchar','nchar')
                   AND SC.object_id = ST.object_id
                 ORDER BY SC.name
                FOR XML PATH('')
            )
      FROM  SYS.tables ST
      JOIN @CheckTableNames chktbls
                ON chktbls.Tablename = ST.name
      JOIN SYS.schemas SCh
        ON ST.schema_id = SCh.schema_id
     WHERE ST.name <> 'SearchTMP'
      GROUP BY ST.object_id, SCh.name + '.' + ST.NAME ;

      UPDATE @SQLTbl
         SET SQLStatement = 'SELECT * INTO SearchTMP FROM ' + Tablename + ' WHERE ' + substring(WHEREClause,1,len(WHEREClause)-5)

      DELETE FROM @SQLTbl
       WHERE WHEREClause IS NULL

    WHILE EXISTS (SELECT 1 FROM @SQLTbl WHERE ISNULL(Execstatus ,0) = 0)
    BEGIN

        SELECT TOP 1 @tmpTblname = Tablename , @sql = SQLStatement
          FROM @SQLTbl
         WHERE ISNULL(Execstatus ,0) = 0



         IF @GenerateSQLOnly = 0
         BEGIN

            IF OBJECT_ID('SearchTMP','U') IS NOT NULL
                DROP TABLE SearchTMP
            EXEC (@SQL)

            IF EXISTS(SELECT 1 FROM SearchTMP)
            BEGIN
                SELECT Tablename=@tmpTblname,* FROM SearchTMP
            END

         END
         ELSE
         BEGIN
             PRINT REPLICATE('-',100)
             PRINT @tmpTblname
             PRINT REPLICATE('-',100)
             PRINT replace(@sql,'INTO SearchTMP','')
         END

         UPDATE @SQLTbl
            SET Execstatus = 1
          WHERE Tablename = @tmpTblname

    END

    SET NOCOUNT OFF

go


답변

이전에 제시된 솔루션이 유효하고 작동하지만, 적어도 내가보기에는 더 깨끗하고 우아하며 성능이 더 좋은 코드를 겸손하게 제공합니다.

첫째로, 다음과 같은 질문이있을 수 있습니다. 전역 적으로 맹목적으로 문자열을 찾기 위해 코드 조각이 필요한 이유는 무엇입니까? 헤이, 그들은 이미 전체 텍스트를 발명했습니다.

내 대답은 주로 시스템 통합 프로젝트에 있으며, 거의 발생하지 않는 새롭고 누적되지 않은 데이터베이스를 배울 때마다 데이터가 기록 된 위치를 찾는 것이 중요합니다.

또한 내가 제시하는 코드는 데이터베이스 전체에서 텍스트를 검색하고 대체하는 더 강력하고 위험한 스크립트의 제거 된 버전입니다.

CREATE TABLE #result(
  id      INT IDENTITY, -- just for register seek order
  tblName VARCHAR(255),
  colName VARCHAR(255),
  qtRows  INT
)
go

DECLARE @toLookFor VARCHAR(255)
SET @toLookFor = '[input your search criteria here]'

DECLARE cCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT
  '[' + usr.name + '].[' + tbl.name + ']' AS tblName,
  '[' + col.name + ']' AS colName,
  LOWER(typ.name) AS typName
FROM
  sysobjects tbl
    INNER JOIN(
      syscolumns col
        INNER JOIN systypes typ
        ON typ.xtype = col.xtype
    )
    ON col.id = tbl.id
    --
    LEFT OUTER JOIN sysusers usr
    ON usr.uid = tbl.uid

WHERE tbl.xtype = 'U'
  AND LOWER(typ.name) IN(
        'char', 'nchar',
        'varchar', 'nvarchar',
        'text', 'ntext'
      )
ORDER BY tbl.name, col.colorder
--
DECLARE @tblName VARCHAR(255)
DECLARE @colName VARCHAR(255)
DECLARE @typName VARCHAR(255)
--
DECLARE @sql  NVARCHAR(4000)
DECLARE @crlf CHAR(2)

SET @crlf = CHAR(13) + CHAR(10)

OPEN cCursor
FETCH cCursor
INTO @tblName, @colName, @typName

WHILE @@fetch_status = 0
BEGIN
  IF @typName IN('text', 'ntext')
  BEGIN
    SET @sql = ''
    SET @sql = @sql + 'INSERT INTO #result(tblName, colName, qtRows)' + @crlf
    SET @sql = @sql + 'SELECT @tblName, @colName, COUNT(*)' + @crlf
    SET @sql = @sql + 'FROM ' + @tblName + @crlf
    SET @sql = @sql + 'WHERE PATINDEX(''%'' + @toLookFor + ''%'', ' + @colName + ') > 0' + @crlf
  END
  ELSE
  BEGIN
    SET @sql = ''
    SET @sql = @sql + 'INSERT INTO #result(tblName, colName, qtRows)' + @crlf
    SET @sql = @sql + 'SELECT @tblName, @colName, COUNT(*)' + @crlf
    SET @sql = @sql + 'FROM ' + @tblName + @crlf
    SET @sql = @sql + 'WHERE ' + @colName + ' LIKE ''%'' + @toLookFor + ''%''' + @crlf
  END

  EXECUTE sp_executesql
            @sql,
            N'@tblName varchar(255), @colName varchar(255), @toLookFor varchar(255)',
            @tblName, @colName, @toLookFor

  FETCH cCursor
  INTO @tblName, @colName, @typName
END

SELECT *
FROM #result
WHERE qtRows > 0
ORDER BY id
GO

DROP TABLE #result
go


답변

응용 프로그램에서 “데이터를 가져 오는”경우 현명한 것은 응용 프로그램을 실행하는 동안 프로파일 러를 사용하고 데이터베이스를 프로파일 링하는 것입니다. 추적 한 다음 해당 문자열에 대한 결과를 검색합니다.


답변

Microsoft SQL Server Management Studio 및 Microsoft SQL Server Management Studio Express 용 SSMS 도구 PACK 추가 기능 (추가 기능)은 필요한 작업을 정확히 수행합니다. 더 큰 데이터베이스에서는 검색하는 데 약간의 시간이 걸리지 만 예상 할 수 있습니다. 또한 처음에 SQL Server Management Studio에 포함되어야하는 멋진 기능이 많이 포함되어 있습니다. 시도해보십시오 www.ssmstoolspack.com/

도구를 실행하려면 SQL Server Management Studio 용 SP2가 설치되어 있어야합니다.


답변

나는 원래 Narayana Vyas Kondreddi가 2002 년에 쓴 대본을 각색했습니다 . 대신 patindex를 사용하여 text / ntext 필드도 확인하도록 where 절을 변경했습니다. 결과 테이블도 약간 변경했습니다. 불합리하게 변수 이름을 변경하고 선호하는대로 정렬했습니다 (Kondetti 씨를 무시하지 않음). 사용자는 검색된 데이터 유형을 변경할 수 있습니다. 중간 처리 쿼리를 허용하기 위해 전역 테이블을 사용했지만 영구 테이블이 더 현명한 방법 일 수 있습니다.

/* original script by Narayana Vyas Kondreddi, 2002 */
/* adapted by Oliver Holloway, 2009 */

/* these lines can be replaced by use of input parameter for a proc */
declare @search_string varchar(1000);
set @search_string = 'what.you.are.searching.for';

/* create results table */
create table ##string_locations (
  table_name varchar(1000),
  field_name varchar(1000),
  field_value varchar(8000)
)
;
/* special settings */
set nocount on
;
/* declare variables */
declare
  @table_name varchar(1000),
  @field_name varchar(1000)
;
/* variable settings */
set @table_name = ''
;
set @search_string = QUOTENAME('%' + @search_string + '%','''')
;
/* for each table */
while @table_name is not null
begin

  set @field_name = ''
  set @table_name = (
    select MIN(QUOTENAME(table_schema) + '.' + QUOTENAME(table_name))
    from INFORMATION_SCHEMA.TABLES
    where
      table_type = 'BASE TABLE' and
      QUOTENAME(table_schema) + '.' + QUOTENAME(table_name) > @table_name and
      OBJECTPROPERTY(OBJECT_ID(QUOTENAME(table_schema) + '.' + QUOTENAME(table_name)), 'IsMSShipped') = 0
  )

  /* for each string-ish field */
  while (@table_name is not null) and (@field_name is not null)
  begin
    set @field_name = (
      select MIN(QUOTENAME(column_name))
      from INFORMATION_SCHEMA.COLUMNS
      where
        table_schema    = PARSENAME(@table_name, 2) and
        table_name  = PARSENAME(@table_name, 1) and
        data_type in ('char', 'varchar', 'nchar', 'nvarchar', 'text', 'ntext') and
        QUOTENAME(column_name) > @field_name
    )

    /* search that field for the string supplied */
    if @field_name is not null
    begin
      insert into ##string_locations
      exec(
        'select ''' + @table_name + ''',''' + @field_name + ''',' + @field_name +
        'from ' + @table_name + ' (nolock) ' +
        'where patindex(' + @search_string + ',' + @field_name + ') > 0'  /* patindex works with char & text */
      )
    end
    ;
  end
  ;
end
;

/* return results */
select table_name, field_name, field_value from ##string_locations (nolock)
;
/* drop temp table */
--drop table ##string_locations
;


답변

이미 게시 된 다른 답변은 똑같이 잘 작동하거나 더 잘 작동 할 수 있지만 사용하지 않았습니다. 그러나 내가 사용한 다음 SQL은 거대한 (그리고 매우 체계적이지 않은) SQL Server 데이터베이스로 큰 시스템을 리버스 엔지니어링하려고 할 때 정말 도움이되었습니다.

이것은 내 코드가 아닙니다. 원저자를 신용하고 싶지만 더 이상 기사 링크를 찾을 수 없습니다.

Use
go

declare @SearchChar varchar(8000)
Set @SearchChar =  -- Like 'A%', '11/11/2006'

declare @CMDMain varchar(8000), @CMDMainCount varchar(8000),@CMDJoin varchar(8000)
declare @ColumnName varchar(100),@TableName varchar(100)

declare dbTable cursor for
SELECT
Distinct b.Name as TableName
FROM
sysobjects b
WHERE
b.type='u' and b.Name  'dtproperties'
order by b.name
open dbTable
fetch next from dbTable into @TableName

WHILE @@FETCH_STATUS = 0
BEGIN
declare db cursor for
SELECT
c.Name as ColumnName
FROM
sysobjects b,
syscolumns c
WHERE
C.id = b.id and
b.type='u' and b.Name = @TableName
order by b.name
open db
fetch next from db into @ColumnName
set @CMDMain = 'SELECT ' + char(39) + @TableName + char(39) + ' as TableName,'+
' ['+ @TableName + '].* FROM [' + @TableName + ']'+
' WHERE '
set @CMDMainCount = 'SELECT Count(*) FROM [' + @TableName + '] Where '
Set @CMDJoin = ''
WHILE @@FETCH_STATUS = 0
BEGIN
set @CMDJoin = @CMDJoin + 'Convert(varchar(5000),[' +@ColumnName + ']) like ' + char(39) + @SearchChar + char(39) + ' OR '

fetch next from db into @ColumnName
end
close db
deallocate db

Set @CMDMainCount = 'If ('+ @CMDMainCount + Left(@CMDJoin, len(@CMDJoin) - 3)+ ') > 0 Begin '
Set @CMDMain = @CMDMainCount + @CMDMain + Left(@CMDJoin, len(@CMDJoin) - 3)
Set @CMDMain = @CMDMain + ' End '

Print @CMDMain

exec (@CMDMain)
fetch next from dbTable into @TableName
end
close dbTable
deallocate dbTable