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


78

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

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


1
이것도 참조하십시오., stackoverflow.com/questions/13174627/…
NoNaMe

답변:


93

이 코드는 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

1
"회사의 아무도 데이터베이스를 이해하지 못한다면 당신은 상당히 엉망이 된 것입니다."-예, 이것은 일반적으로 아마도 새롭고 유일한 IT 직원이 이와 같은 것을 필요로 할 때입니다. 경영진이이를 적절히 수행하기 위해 자금을 승인하지 않기 때문입니다. 추신. 이는 2012 SQL 서버에 나를 위해 확인 일
BeowulfNode42

2
모든 개체가 dbo의 소유가 아닌 경우 어떻게합니까? 어떻게 조정합니까?
폴 카.

비 dbo 개체를 처리하도록 스크립트를 업데이트했습니다. 또한 INFORMATION_SCHEMA 테이블을 사용하도록 변경했습니다. 이는 향후 버전에서 사용할 수있을뿐만 아니라 이론적으로 Oracle, MySQL 등에서도 작동해야 함을 의미합니다. 마지막으로 QUOTENAME모든 객체 이름이 다음과 같은 작업을 처리 하는 데 사용하도록 변경했습니다. 테이블 이름의 공백.
Tom H

회사의 아무도 스키마를 모르는 데이터베이스로 작업하는 것은 드문 일이 아닙니다. 회사에서 구입 한 소프트웨어에 대해 데이터베이스에 쿼리하라는 요청을 자주받습니다. 공급 업체가 도움을 요청하는 경우 도움 없이도 스키마를 파악할 수 있는지 확인하는 것이 좋습니다.
NL3294

매우 도움이됩니다. 하지만 내가 UniqueIdentifiers 검색되면서 COLLATION_NAME이 NULL 조건을지지 않습니다 제거해야
Ananth

35

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

1
이 저장된 proc은 하나의 select 문에서 행의 모든 ​​열을 확인하므로 다른 제안보다 훨씬 효율적이지만 열이 일치하는 셀을 반드시 제공하지는 않습니다. 또한 전체 % wildcard % 검색을 원한다고 가정하지 않습니다. 또한 임시 테이블을 생성하지 않으므로 코드를 실행하기 전에 확인하지 않으면 번거 롭습니다. 검색중인 db를 수정하지 않으려면 전체를 BEGIN / DECLARE / END 블록으로 변환하고 편리한 곳에 보관하십시오.
Mayyit 2014

사용자에게 한 가지 더 제안 사항-결과 집합이 특히 클 수 있고 항목의 위치를 ​​확인하기 위해 "시작"하려는 경우 "TOP 100"제한 등을 포함하도록 위를 수정합니다.
Mayyit 2014

임시 테이블을 만들지 않는 것에 대한 내 말을 되돌려 .. 그것보다 조금 더 나쁘다, 심지어! "SearchTMP"테이블이 생성됩니다.
Mayyit 2014

28

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

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

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

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

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

이것은 SQL Server 2012에서 저에게 매우
효과적

@Marcus Vinicius Pompeu이 동일한 쿼리를 사용하여 2 개의 문자열을 검색 할 수 있습니까?
Eric S

Marcus는 신경 쓰지 마세요. 제가 찾고있는 2 개의 현은 똑같지 만 마지막 캐릭터입니다. 마지막 캐릭터를 잘라내겠습니다. 그건 그렇고 훌륭한 대답입니다. +1
Eric S

1
@EricS, 당신은 나에게 도전을 제시했습니다! 2 ~ 3 일 후에 더 나은 솔루션을 제시하겠습니다. 문안 인사.
Marcus Vinicius Pompeu 2016 년

@MarcusViniciusPompeu haha ​​감사합니다. 행운을 빕니다. 나는 그것을 위해 나의 열린 상태를 유지할 것입니다.
에릭 S

13

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


8

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가 설치되어 있어야합니다.


6

나는 원래 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
;

4

이미 게시 된 다른 답변은 똑같이 잘 작동하거나 더 잘 작동 할 수 있지만 사용하지 않았습니다. 그러나 내가 사용한 다음 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


4

사실 저는 MikeW (+1)에 동의합니다.이 경우 프로파일 러를 사용하는 것이 좋습니다.

어쨌든 db의 모든 (n) varchar 열을 가져 와서 검색해야하는 경우. 아래를 참조하십시오. INFORMATION_SCHEMA.Tables + 동적 SQL을 사용한다고 가정합니다. 일반 검색 :

DECLARE @SearchText VARCHAR(100) 
SET @SearchText = '12'
DECLARE @Tables TABLE(N INT, TableName VARCHAR(100), ColumnNamesCSV VARCHAR(2000), SQL VARCHAR(4000))

INSERT INTO @Tables (TableName, ColumnNamesCSV)
SELECT  T.TABLE_NAME AS TableName, 
        ( SELECT C.Column_Name + ',' 
          FROM   INFORMATION_SCHEMA.Columns C 
          WHERE  T.TABLE_NAME = C.TABLE_NAME 
                 AND C.DATA_TYPE IN ('nvarchar','varchar') 
                 FOR XML PATH('')
        )
FROM    INFORMATION_SCHEMA.Tables T 

DELETE FROM @Tables WHERE ColumnNamesCSV IS NULL

INSERT INTO @Tables (N, TableName, ColumnNamesCSV)
SELECT ROW_NUMBER() OVER(ORDER BY TableName), TableName, ColumnNamesCSV  
FROM   @Tables

DELETE FROM @Tables WHERE N IS NULL

UPDATE @Tables 
SET ColumnNamesCSV = SUBSTRING(ColumnNamesCSV, 0, LEN(ColumnNamesCSV))

UPDATE @Tables 
SET SQL = 'SELECT * FROM ['+TableName+'] WHERE '''+@SearchText+''' IN ('+ColumnNamesCSV+')'

DECLARE @C INT, 
        @I INT, 
        @SQL VARCHAR(4000)

SELECT @I = 1, 
       @C = COUNT(1) 
FROM   @Tables

WHILE @I <= @C BEGIN
    SELECT @SQL = SQL FROM @Tables WHERE N = @I
    SET @I = @I+1
    EXEC(@SQL)
END

LIKE 절이있는 하나 :

DECLARE @SearchText VARCHAR(100) 
SET @SearchText = '12'

DECLARE @Tables TABLE(N INT, TableName VARCHAR(100), ColumnNamesCSVLike VARCHAR(2000), LIKESQL VARCHAR(4000))

INSERT INTO @Tables (TableName, ColumnNamesCSVLike)
SELECT   T.TABLE_NAME AS TableName, 
         (   SELECT  C.Column_Name + ' LIKE ''%'+@SearchText+'%'' OR ' 
             FROM    INFORMATION_SCHEMA.Columns C 
             WHERE   T.TABLE_NAME = C.TABLE_NAME 
                     AND C.DATA_TYPE IN ('nvarchar','varchar') 
          FOR XML PATH(''))
FROM     INFORMATION_SCHEMA.Tables T

DELETE FROM @Tables WHERE ColumnNamesCSVLike IS NULL

INSERT INTO @Tables (N, TableName, ColumnNamesCSVLike)
SELECT ROW_NUMBER() OVER(ORDER BY TableName), TableName, ColumnNamesCSVLike 
FROM @Tables

DELETE FROM @Tables WHERE N IS NULL

UPDATE @Tables 
SET  ColumnNamesCSVLike = SUBSTRING(ColumnNamesCSVLike, 0, LEN(ColumnNamesCSVLike)-2)

UPDATE @Tables SET LIKESQL = 'SELECT * FROM ['+TableName+'] WHERE '+ColumnNamesCSVLike

DECLARE @C INT, 
        @I INT, 
        @LIKESQL VARCHAR(4000)

SELECT @I = 1, 
       @C = COUNT(1) 
FROM @Tables

WHILE @I <= @C BEGIN
    SELECT @LIKESQL = LIKESQL FROM @Tables WHERE N = @I
    SET @I = @I +1
    EXEC(@LIKESQL)
END

3

@NLwino, 키워드 사용에 대한 몇 가지 오류가있는 좋은 쿼리입니다. 키워드를 []로 감싸고 char 및 ntext 열을보기 위해 약간 수정해야했습니다.

    DECLARE @searchstring  NVARCHAR(255)
    SET @searchstring = '%WDB1014%'

    DECLARE @sql NVARCHAR(max)

    SELECT @sql = STUFF((
      SELECT ' UNION ALL SELECT ''' + TABLE_NAME + ''' AS tbl, ''' + COLUMN_NAME + ''' AS col, [' + COLUMN_NAME + '] AS val' + 
        ' FROM ' + TABLE_SCHEMA + '.[' + TABLE_NAME + 
        '] WHERE [' + COLUMN_NAME + '] LIKE ''' + @searchstring + ''''
        FROM INFORMATION_SCHEMA.COLUMNS 
        WHERE DATA_TYPE in ('nvarchar', 'varchar', 'char', 'ntext')
                  FOR XML PATH('')
             ) ,1, 11, '')

    Exec (@sql)

2.5GB 데이터베이스에서 실행했고 51 초 만에 돌아 왔습니다.


1
@NLwino의 게시물을 편집 한 경우 새 답변을 게시하는 것보다 그의 게시물을 편집해야합니다 (평판이 충분한 경우).
John Parker

3

이것은 커서 나 그와 유사한 것을 사용하지 않고 단지 하나의 동적 쿼리를 사용합니다.

또한 LIKE. 그것이 내가 필요한 것이기 때문에. 그것은 모든 스키마, 모든 테이블 작동 만 쿼리는 그 컬럼의 NVARCHAR또는 VARCHAR그들이 UDDT이 있더라도합니다.

DECLARE @searchstring  NVARCHAR(255)
SET @searchstring = '%searchstring%'

DECLARE @sql NVARCHAR(max)

SELECT @sql = STUFF((
    SELECT ' UNION ALL SELECT ''' + TABLE_NAME + ''' AS tablename, ''' + COLUMN_NAME + ''' AS columnname, ' + COLUMN_NAME + ' AS valuename' + 
    ' FROM ' + TABLE_SCHEMA + '.' + TABLE_NAME + 
    ' WHERE ' + COLUMN_NAME + ' LIKE ''' + @searchstring + ''''
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE DATA_TYPE in ('nvarchar', 'varchar')
    FOR XML PATH('')
) ,1, 11, '')

EXEC(@sql)

출력은 테이블, 열 및 값을 제공합니다. 작은 데이터베이스에서 실행하는 데 걸리는 시간은 약 3 초 였고 결과는 약 3000 개였습니다.


2
이걸 실행하면 '테이블'키워드 근처에 잘못된 구문이라는 오류가 발생합니다.
Karl Glennon 2013-07-02

내가 생각 @KarlGlennon, 당신은 변경해야 AS table하는 AS [table]등등.
shA.t apr

참고 :이 쿼리의 결과에는 뷰와 테이블이 포함됩니다.
shA.t apr

2
/*
This procedure is for finding any string or date in all tables
if search string is date, its format should be yyyy-MM-dd
eg. 2011-07-05
*/

-- ================================================
-- Exec SearchInTables 'f6f56934-a5d4-4967-80a1-1a2223b9c7b1'

-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      <Joshy,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE SearchInTables
@myValue nvarchar(1000)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
        DECLARE @searchsql nvarchar(max)
        DECLARE @table_name nvarchar(1000)
        DECLARE @Schema_name nvarchar(1000)
        DECLARE @ParmDefinition nvarchar(500)
        DECLARE @XMLIn nvarchar(max)
        SET @ParmDefinition = N'@XMLOut varchar(max) OUTPUT'

        SELECT A.name,b.name 
        FROM sys.tables A 
            INNER JOIN sys.schemas B ON A.schema_id=B.schema_id
        WHERE A.name like 'tbl_Tax_Sections' 

        DECLARE tables_cur CURSOR FOR 
                            SELECT A.name,b.name FOM sys.tables A 
                            INNER JOIN sys.schemas B ON A.schema_id=B.schema_id
                            WHERE A.type = 'U'  
        OPEN tables_cur  
        FETCH NEXT FROM tables_cur INTO @table_name , @Schema_name 
            WHILE (@@FETCH_STATUS = 0) 
            BEGIN
                SET @searchsql ='SELECT @XMLOut=(SELECT PATINDEX(''%'+ @myValue+ '%'''
                SET @searchsql =@searchsql  + ', (SELECT * FROM '+@Schema_name+'.'+@table_name+' FOR XML AUTO) ))'
                --print @searchsql 
                EXEC sp_executesql @searchsql, @ParmDefinition, @XMLOut=@XMLIn OUTPUT
                --print @XMLIn 

                IF @XMLIn <> 0 PRINT @Schema_name+'.'+@table_name

                FETCH NEXT FROM tables_cur INTO @table_name , @Schema_name 

            END
        CLOSE tables_cur 
        DEALLOCATE tables_cur 
    RETURN
END
GO

1

"내가 얻은 데이터의 출처를 찾으려면"SQL 프로필러를 시작하고 보고서 또는 응용 프로그램을 시작하면 데이터베이스에 대해 실행 된 모든 쿼리를 볼 수 있습니다.


1

커서FOR XML을 사용하지 않고 데이터베이스의 모든 행에서 문자열을 찾는 가장 쉬운 방법이라고 생각합니다 .

CREATE PROCEDURE SPFindAll (@find VARCHAR(max) = '')
AS
BEGIN
    SET NOCOUNT ON;
    --
    DECLARE @query VARCHAR(max) = ''

    SELECT  @query = @query + 
            CASE 
                WHEN @query = '' THEN '' 
                ELSE ' UNION ALL '
            END +
            'SELECT ''' + s.name + ''' As schemaName, ''' + t.name + ''' As tableName, ''' + c.name + ''' As ColumnName, [' + c.name + '] COLLATE DATABASE_DEFAULT As [Data] FROM [' + s.name + '].[' + t.name + '] WHERE [' + c.name + '] Like ''%' + @find + '%'''
    FROM 
        sys.schemas s
        INNER JOIN
        sys.tables t ON s.[schema_id] = t.[schema_id]
        INNER JOIN 
        sys.columns c ON t.[object_id] = c.[object_id]
        INNER JOIN
        sys.types ty ON c.user_type_id = ty.user_type_id
    WHERE
        ty.name LIKE '%char'

    EXEC(@query)
END

이 저장 프로 시저를 만들면 다음과 같이 찾을 문자열에 대해 실행할 수 있습니다.

EXEC SPFindAll 'Hello World'

결과는 다음과 같습니다.

schemaName | tableName | columnName | Data
-----------+-----------+------------+-----------------------
schema1    | Table1    | Column1    | Hello World
schema1    | Table1    | Column1    | Hello World!
schema1    | Table2    | Column1    | I say "Hello World".
schema1    | Table2    | Column2    | Hello World

0

또는 여기에서 내 쿼리를 사용할 수 있습니다. 검색하려는 각 DB에 대해 sProcs를 생성하는 것보다 더 간단해야합니다. FullParam SQL Blog

/* Reto Egeter, fullparam.wordpress.com */

DECLARE @SearchStrTableName nvarchar(255), @SearchStrColumnName nvarchar(255), @SearchStrColumnValue nvarchar(255), @SearchStrInXML bit, @FullRowResult bit, @FullRowResultRows int
SET @SearchStrColumnValue = '%searchthis%' /* use LIKE syntax */
SET @FullRowResult = 1
SET @FullRowResultRows = 3
SET @SearchStrTableName = NULL /* NULL for all tables, uses LIKE syntax */
SET @SearchStrColumnName = NULL /* NULL for all columns, uses LIKE syntax */
SET @SearchStrInXML = 0 /* Searching XML data may be slow */

IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (TableName nvarchar(128), ColumnName nvarchar(128), ColumnValue nvarchar(max),ColumnType nvarchar(20))

SET NOCOUNT ON

DECLARE @TableName nvarchar(256) = '',@ColumnName nvarchar(128),@ColumnType nvarchar(20), @QuotedSearchStrColumnValue nvarchar(110), @QuotedSearchStrColumnName nvarchar(110)
SET @QuotedSearchStrColumnValue = QUOTENAME(@SearchStrColumnValue,'''')
DECLARE @ColumnNameTable TABLE (COLUMN_NAME nvarchar(128),DATA_TYPE nvarchar(20))

WHILE @TableName IS NOT NULL
BEGIN
    SET @TableName = 
    (
        SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME))
        FROM    INFORMATION_SCHEMA.TABLES
        WHERE       TABLE_TYPE = 'BASE TABLE'
            AND TABLE_NAME LIKE COALESCE(@SearchStrTableName,TABLE_NAME)
            AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName
            AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
    )
    IF @TableName IS NOT NULL
    BEGIN
        DECLARE @sql VARCHAR(MAX)
        SET @sql = 'SELECT QUOTENAME(COLUMN_NAME),DATA_TYPE
                FROM    INFORMATION_SCHEMA.COLUMNS
                WHERE       TABLE_SCHEMA    = PARSENAME(''' + @TableName + ''', 2)
                AND TABLE_NAME  = PARSENAME(''' + @TableName + ''', 1)
                AND DATA_TYPE IN (' + CASE WHEN ISNUMERIC(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@SearchStrColumnValue,'%',''),'_',''),'[',''),']',''),'-','')) = 1 THEN '''tinyint'',''int'',''smallint'',''bigint'',''numeric'',''decimal'',''smallmoney'',''money'',' ELSE '' END + '''char'',''varchar'',''nchar'',''nvarchar'',''timestamp'',''uniqueidentifier''' + CASE @SearchStrInXML WHEN 1 THEN ',''xml''' ELSE '' END + ')
                AND COLUMN_NAME LIKE COALESCE(' + CASE WHEN @SearchStrColumnName IS NULL THEN 'NULL' ELSE '''' + @SearchStrColumnName + '''' END  + ',COLUMN_NAME)'
        INSERT INTO @ColumnNameTable
        EXEC (@sql)
        WHILE EXISTS (SELECT TOP 1 COLUMN_NAME FROM @ColumnNameTable)
        BEGIN
            PRINT @ColumnName
            SELECT TOP 1 @ColumnName = COLUMN_NAME,@ColumnType = DATA_TYPE FROM @ColumnNameTable
            SET @sql = 'SELECT ''' + @TableName + ''',''' + @ColumnName + ''',' + CASE @ColumnType WHEN 'xml' THEN 'LEFT(CAST(' + @ColumnName + ' AS nvarchar(MAX)), 4096),''' 
            WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ @ColumnName + '),'''
            ELSE 'LEFT(' + @ColumnName + ', 4096),''' END + @ColumnType + ''' 
                    FROM ' + @TableName + ' (NOLOCK) ' +
                    ' WHERE ' + CASE @ColumnType WHEN 'xml' THEN 'CAST(' + @ColumnName + ' AS nvarchar(MAX))' 
                    WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ @ColumnName + ')'
                    ELSE @ColumnName END + ' LIKE ' + @QuotedSearchStrColumnValue
            INSERT INTO #Results
            EXEC(@sql)
            IF @@ROWCOUNT > 0 IF @FullRowResult = 1 
            BEGIN
                SET @sql = 'SELECT TOP ' + CAST(@FullRowResultRows AS VARCHAR(3)) + ' ''' + @TableName + ''' AS [TableFound],''' + @ColumnName + ''' AS [ColumnFound],''FullRow>'' AS [FullRow>],*' +
                    ' FROM ' + @TableName + ' (NOLOCK) ' +
                    ' WHERE ' + CASE @ColumnType WHEN 'xml' THEN 'CAST(' + @ColumnName + ' AS nvarchar(MAX))' 
                    WHEN 'timestamp' THEN 'master.dbo.fn_varbintohexstr('+ @ColumnName + ')'
                    ELSE @ColumnName END + ' LIKE ' + @QuotedSearchStrColumnValue
                EXEC(@sql)
            END
            DELETE FROM @ColumnNameTable WHERE COLUMN_NAME = @ColumnName
        END 
    END
END
SET NOCOUNT OFF

SELECT TableName, ColumnName, ColumnValue, ColumnType, COUNT (*) AS Count FROM #Results GROUP BY TableName, ColumnName, ColumnValue, ColumnType


0

이 쿼리는 당신을 위해 일을 할 수 있습니다.

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

SET @search_string = 'StringtoSearch'

DECLARE tables_cur CURSOR FOR SELECT ss.name +'.'+ so.name [name], object_id FROM sys.objects so INNER JOIN sys.schemas ss ON so.schema_id = ss.schema_id WHERE  type = 'U'

OPEN tables_cur

FETCH NEXT FROM tables_cur INTO @table_name, @table_id

WHILE (@@FETCH_STATUS = 0)
BEGIN
    DECLARE columns_cur CURSOR FOR SELECT name FROM sys.columns WHERE object_id = @table_id 
        AND system_type_id IN (167, 175, 231, 239, 99)

    OPEN columns_cur

    FETCH NEXT FROM columns_cur INTO @column_name
        WHILE (@@FETCH_STATUS = 0)
        BEGIN
            SET @sql_string = 'IF EXISTS (SELECT * FROM ' + @table_name + ' WHERE [' + @column_name + '] 
            LIKE ''%' + @search_string + '%'') PRINT ''' + @table_name + ', ' + @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_name, @table_id
END

CLOSE tables_cur
DEALLOCATE tables_cur
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.