[MS-SQL] DB에서 특정 문자열을 찾고 싶을 때
가끔 일을 하다보면 특정문자가 포함된 테이블이 뭔지 찾고싶을때가 있다.
혹은 단편적인 단서로 실마리를 찾아야 할 때 라던가…
그래서 두가지 방법을 소개해본다.
1) 전체 DB에서 특정 문자열을 찾고싶을 때
USE [kitty] GO /****** Object: StoredProcedure [dbo].[spSearchOnAlldb] Script Date: 2018-08-16 오후 5:12:10 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO /*************************************************************************/ /* Procedure of search of a phrase on all database */ /* Is developed by Oufimtsev Gleb, MCSE */ /* */ /* gvu@newmail.ru, http://www.gvu.newmail.ru */ /* +7 (095) 178-40-92, Moscow, Russia */ /*************************************************************************/ ALTER PROCEDURE [dbo].[spSearchOnAlldb] @phrase varchar(4000), @OutFullRecords bit=0 AS /* To apply so: exec spSearchOnAlldb 'Sugar%' exec spSearchOnAlldb '%soft%' exec spSearchOnAlldb '_5234_57%', 1 exec spSearchOnAlldb M_cro_oft */ declare @sql varchar(4000) declare @tbl varchar(128) declare @col varchar(128) declare @id_present bit declare @is_char_phrase bit declare @min_len int declare @loop_idx int declare @loop_chr char(1) set nocount on if IsNull(@phrase,'')='' begin raiserror('Phrase is absent',16,-1) return end select @loop_idx=1, @is_char_phrase=0, @min_len=0 while @loop_idx<=LEN(@phrase) begin set @loop_chr=SUBSTRING(@phrase,@loop_idx,1) if @loop_chr not in ('%','_') set @min_len=@min_len+1 if @is_char_phrase=0 and @loop_chr not in ('%','_','0','1','2','3','4','5','6','7','8','9','.') set @is_char_phrase=1 set @loop_idx=@loop_idx+1 end create table #tbl_res (TableName varchar(128) not NULL, ColumnName varchar(128) not NULL, Id int NULL, ColumnValue nvarchar(max) not NULL) declare CRR cursor local fast_forward for select t.name, c.name, 1 from sysobjects t, syscolumns c where t.type='U' and c.id=t.id and c.status&0x80=0 -- Not IDENTITY and exists (select * from syscolumns c2 where t.id=c2.id and c2.status&0x80=0x80 and c2.xtype in (48,52,56)) and ( (@is_char_phrase=1 and c.xtype in (175,239,99,231,35,167) and c.length>=@min_len) -- char only or (@is_char_phrase=0 and c.xtype not in (34,165,173,189,61,58,36))) -- char and numeric union select t.name, c.name, 0 from sysobjects t, syscolumns c where t.type='U' and c.id=t.id and not exists (select * from syscolumns c2 where t.id=c2.id and c2.status&0x80=0x80 and c2.xtype in (48,52,56)) and ( (@is_char_phrase=1 and c.xtype in (175,239,99,231,35,167) and c.length>=@min_len) -- char only or (@is_char_phrase=0 and c.xtype not in (34,165,173,189,61,58,36))) -- char and numeric order by 1,2 open CRR fetch CRR into @tbl, @col, @id_present while @@FETCH_STATUS=0 begin if @OutFullRecords=0 begin set @sql='insert into #tbl_res (TableName,ColumnName,Id,ColumnValue) ' +'select '+char(39)+@tbl+char(39)+', ' +char(39)+@col+char(39)+', ' if @id_present=1 set @sql=@sql+'IDENTITYCOL, ' else set @sql=@sql+'NULL, ' set @sql=@sql+'convert(nvarchar(3500),'+@col+') ' +'from '+@tbl+' (nolock) ' +'where convert(nvarchar(4000),'+@col+') like '+char(39)+@phrase+char(39) end if @OutFullRecords=1 begin set @sql='if exists (select * from '+@tbl+' (nolock) ' +'where convert(nvarchar(4000),'+@col+') like '+char(39)+@phrase+char(39)+') ' +'select '+char(39)+@tbl+char(39)+' TableName, '+char(39)+@col+char(39)+' ColumnName, * ' +'from '+@tbl+' (nolock) where convert(nvarchar(4000),'+@col+') like '+char(39)+@phrase+char(39) end exec(@sql) fetch CRR into @tbl, @col, @id_present end close CRR deallocate CRR if @OutFullRecords=0 begin -- For the clients supporting new types: --exec('select * from #tbl_res order by 1,2,3') -- For the clients who are not supporting new types: exec('select TableName, ColumnName, Id, convert(nvarchar(255),ColumnValue) ColumnValue from #tbl_res order by 1,2,3') end drop table #tbl_res
사용 예제
exec spSearchOnAlldb '%찾고싶은 문자열%'
2) 또 다른 방법.
USE [Kitty] GO /****** Object: StoredProcedure [dbo].[U_SearchOnAlldb] Script Date: 2020-01-23 오전 10:53:20 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO /*************************************************************************/ /* 전체 DB에서 특정 문자열 검색 */ /* Kim Kitty */ /*************************************************************************/ --exec [dbo].[U_SearchOnAlldb] 'Kitty' ----------------------------------------------------- CREATE PROC [dbo].[U_SearchOnAlldb] ( @SearchStr nvarchar(100) ) AS BEGIN DECLARE @Results TABLE(ColumnName nvarchar(370), ColumnValue nvarchar(3630)) SET NOCOUNT ON DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110) SET @TableName = '' SET @SearchStr2 = QUOTENAME('%' + @SearchStr + '%','''') WHILE @TableName IS NOT NULL BEGIN SET @ColumnName = '' SET @TableName = ( SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName AND OBJECTPROPERTY( OBJECT_ID( QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) ), 'IsMSShipped' ) = 0 ) WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL) BEGIN SET @ColumnName = ( SELECT MIN(QUOTENAME(COLUMN_NAME)) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = PARSENAME(@TableName, 2) AND TABLE_NAME = PARSENAME(@TableName, 1) AND DATA_TYPE IN ('char', 'varchar', 'nchar', 'nvarchar') AND QUOTENAME(COLUMN_NAME) > @ColumnName ) IF @ColumnName IS NOT NULL BEGIN INSERT INTO @Results EXEC ( 'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) FROM ' + @TableName + ' (NOLOCK) ' + ' WHERE ' + @ColumnName + ' LIKE ' + @SearchStr2 ) END END END SELECT ColumnName, ColumnValue FROM @Results END
3) 특정 테이블에서 특정문자열을 찾고 싶을 때
USE [kitty] GO /****** Object: StoredProcedure [dbo].[sp_FindStringInTable] Script Date: 2018-08-16 오후 5:11:25 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[sp_FindStringInTable] @stringToFind VARCHAR(100), @schema sysname, @table sysname AS DECLARE @sqlCommand VARCHAR(8000) DECLARE @where VARCHAR(8000) DECLARE @columnName sysname DECLARE @cursor VARCHAR(8000) BEGIN TRY SET @sqlCommand = 'SELECT * FROM [' + @schema + '].[' + @table + '] WHERE' SET @where = '' SET @cursor = 'DECLARE col_cursor CURSOR FOR SELECT COLUMN_NAME FROM ' + DB_NAME() + '.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ''' + @schema + ''' AND TABLE_NAME = ''' + @table + ''' AND DATA_TYPE IN (''char'',''nchar'',''ntext'',''nvarchar'',''text'',''varchar'')' EXEC (@cursor) OPEN col_cursor FETCH NEXT FROM col_cursor INTO @columnName WHILE @@FETCH_STATUS = 0 BEGIN IF @where <> '' SET @where = @where + ' OR' SET @where = @where + ' [' + @columnName + '] LIKE ''' + @stringToFind + '''' FETCH NEXT FROM col_cursor INTO @columnName END CLOSE col_cursor DEALLOCATE col_cursor SET @sqlCommand = @sqlCommand + @where --PRINT @sqlCommand EXEC (@sqlCommand) END TRY BEGIN CATCH PRINT 'There was an error. Check to make sure object exists.' IF CURSOR_STATUS('variable', 'col_cursor') <> -3 BEGIN CLOSE col_cursor DEALLOCATE col_cursor END END CATCH
사용 예제
EXEC sp_FindStringInTable '%찾고싶은 문자열%', 'dbo', 'Table명'