나는 큰 데이터베이스에서 길을 잃었고 내가 얻은 데이터의 출처를 찾을 수 없습니다. SQL Server 2005에서 데이터베이스의 모든 테이블, 행 및 열에서 문자열을 검색 할 수 있는지 궁금합니다.
가능한 경우 아이디어가있는 사람이 있습니까?
답변
이 코드는 SQL 2005에서이를 수행해야하지만 몇 가지주의 사항이 있습니다.
-
엄청나게 느립니다. 몇 개의 테이블 만 가지고있는 작은 데이터베이스에서 테스트했으며 완료하는 데 몇 분이 걸렸습니다. 데이터베이스가 너무 커서 이해할 수 없다면 어쨌든 사용할 수 없을 것입니다.
-
나는 이것을 팔목에 썼다. 나는 오류 처리를하지 않았고 특히 커서를 자주 사용하지 않기 때문에 다른 엉성한 부분이있을 수 있습니다. 예를 들어, 열 커서를 매번 닫거나 할당 해제 / 다시 만드는 대신 열 커서를 새로 고치는 방법이 있다고 생각합니다.
데이터베이스를 이해하지 못하거나 자료가 어디에서 오는지 모른다면 아마 이해하는 사람을 찾아야합니다. 데이터가있는 위치를 찾을 수 있더라도 어딘가에 중복되거나 이해하지 못하는 데이터베이스의 다른 측면이있을 수 있습니다. 회사의 아무도 데이터베이스를 이해하지 못한다면 꽤 엉망인 것입니다.
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