如何在 SQL Server 过程/触发器中查找文本?

Posted

技术标签:

【中文标题】如何在 SQL Server 过程/触发器中查找文本?【英文标题】:How to find a text inside SQL Server procedures / triggers? 【发布时间】:2010-10-15 01:09:45 【问题描述】:

我有一个会改变的链接服务器。一些程序这样调用链接服务器:[10.10.100.50].dbo.SPROCEDURE_EXAMPLE。我们也有触发器在做这种工作。我们需要找到所有使用[10.10.100.50]的地方进行更改。

在 SQL Server Management Studio Express 中,我没有在 Visual Studio 中找到像“在整个数据库中查找”这样的功能。一个特殊的 sys-select 可以帮助我找到我需要的东西吗?

【问题讨论】:

【参考方案1】:

这是我在系统上用来查找文本的过程的一部分......

DECLARE @Search varchar(255)
SET @Search='[10.10.100.50]'

SELECT DISTINCT
    o.name AS Object_Name,o.type_desc
    FROM sys.sql_modules        m 
        INNER JOIN sys.objects  o ON m.object_id=o.object_id
    WHERE m.definition Like '%'+@Search+'%'
    ORDER BY 2,1

【讨论】:

此外,您可以将其添加到结果集中以快速查看包含您搜索的值的文本。 , substring(m.definition, charindex(@Search, m.definition), 100) @ChrisRodriguez,好主意,但请记住,这只是每个过程/触发器/函数中可能有许多匹配项的第一个匹配项 约束 (type = 'C') 无效?【参考方案2】:

你可以像这样找到它

SELECT DISTINCT OBJECT_NAME(id) FROM syscomments WHERE [text] LIKE '%User%'

它将列出不同的存储过程名称,其中包含存储过程中的“用户”等文本。 More info

【讨论】:

请注意,syscomments 表将值存储在 8000 个字符的块中,因此,如果您不幸将要搜索的文本拆分到这些边界之一,您就赢了'用这个方法找不到。【参考方案3】:

[迟到的答案,但希望有用]

使用系统表并不总是能提供 100% 正确的结果,因为某些存储过程和/或视图可能会被加密,在这种情况下,您需要使用 DAC 连接来获取您需要的数据.

我建议使用可以轻松处理加密对象的第三方工具,例如 ApexSQL Search。

如果对象被加密,Syscmets 系统表将为文本列提供空值。

【讨论】:

【参考方案4】:
-- Declare the text we want to search for
DECLARE @Text nvarchar(4000);
SET @Text = 'employee';

-- Get the schema name, table name, and table type for:

-- Table names
SELECT
       TABLE_SCHEMA  AS 'Object Schema'
      ,TABLE_NAME    AS 'Object Name'
      ,TABLE_TYPE    AS 'Object Type'
      ,'Table Name'  AS 'TEXT Location'
FROM  INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '%'+@Text+'%'
UNION
 --Column names
SELECT
      TABLE_SCHEMA   AS 'Object Schema'
      ,COLUMN_NAME   AS 'Object Name'
      ,'COLUMN'      AS 'Object Type'
      ,'Column Name' AS 'TEXT Location'
FROM  INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%'+@Text+'%'
UNION
-- Function or procedure bodies
SELECT
      SPECIFIC_SCHEMA     AS 'Object Schema'
      ,ROUTINE_NAME       AS 'Object Name'
      ,ROUTINE_TYPE       AS 'Object Type'
      ,ROUTINE_DEFINITION AS 'TEXT Location'
FROM  INFORMATION_SCHEMA.ROUTINES 
WHERE ROUTINE_DEFINITION LIKE '%'+@Text+'%'
      AND (ROUTINE_TYPE = 'function' OR ROUTINE_TYPE = 'procedure');

【讨论】:

这不包括所问问题的触发器 适用于视图、存储过程、用户定义的表?对于触发器、函数、约束、规则、默认值【参考方案5】:

这对你有用:

use [ANALYTICS]  ---> put your DB name here
GO
SELECT sm.object_id, OBJECT_NAME(sm.object_id) AS object_name, o.type, o.type_desc, sm.definition
FROM sys.sql_modules AS sm
JOIN sys.objects AS o ON sm.object_id = o.object_id
where sm.definition like '%SEARCH_WORD_HERE%' collate SQL_Latin1_General_CP1_CI_AS
ORDER BY o.type;
GO

【讨论】:

约束 (type = 'C') 无效?【参考方案6】:

很多比每次链接服务器更改时修改存储过程、函数和视图的文本更好的解决方案。以下是一些选项:

    更新链接服务器。不要使用以 IP 地址命名的链接服务器,而是使用资源名称(例如 FinanceDataLinkProd 或类似名称)创建一个新的链接服务器。然后,当您需要更改访问的服务器时,更新链接服务器以指向新服务器(或删除它并重新创建它)。

    虽然很遗憾您无法为链接服务器或架构创建同义词,但您可以为链接服务器上的对象创建同义词。例如,您的过程[10.10.100.50].dbo.SPROCEDURE_EXAMPLE 可以使用别名。也许创建一个模式datalinkprod,然后创建CREATE SYNONYM datalinkprod.dbo_SPROCEDURE_EXAMPLE FOR [10.10.100.50].dbo.SPROCEDURE_EXAMPLE;。然后,编写一个接受链接服务器名称的存储过程,该过程从远程数据库中查询所有潜在对象并(重新)为它们创建同义词。您的所有 SP 和函数只需重写一次以使用以 datalinkprod 开头的同义词名称,然后再从一个链接服务器更改为另一个链接服务器,您只需执行 EXEC dbo.SwitchLinkedServer '[10.10.100.51]'; 并在几分之一秒内使用不同的链接服务器。

可能还有更多选择。我强烈建议使用预处理、配置或间接的高级技术,而不是更改人工编写的脚本。自动更新机器创建的脚本很好,这是预处理。手动做事很糟糕。

【讨论】:

我同意你的建议。但是在像OP描述的情况下,您仍然需要找到所有包含服务器IP的存储过程。即使你只需要做一次,手工完成也可能是很多的工作。 @PaulGroke 是的,这个“大量”工作是根深蒂固的系统中糟糕的技术选择造成的技术债务。需要时间才能从中恢复——偿还应计债务。但我的建议是如何积累技术财富——现在花更多的时间变得更快、更敏捷、更可靠。阅读文章Big Ball of Mud 了解有关此的一些想法。 我的意思是:通过使用其他人在此处发布的 SELECT 语句之一来减少“还清债务”的工作有什么问题? @PaulGroke 快速查找可能引用链接服务器的对象并没有错。但你知道“授人以鱼”而不是“授人以鱼”的那句古老格言吗?是的。那个东西。 @ErikE 事情是——你不是在教他如何钓鱼,只是说如果他钓鱼,他就能得到食物。您的回答是很好的建议,但无助于 OP 实际实施它。添加一种查找这些引用的方法,以便您可以用设计更好的东西替换它们将使这个答案更好。【参考方案7】:
select text
from syscomments
where text like '%your text here%'

【讨论】:

【参考方案8】:

这个是我在SQL2008中试过的,可以一次从所有db中搜索。

Create table #temp1 
(ServerName varchar(64), dbname varchar(64)
,spName varchar(128),ObjectType varchar(32), SearchString varchar(64))

Declare @dbid smallint, @dbname varchar(64), @longstr varchar(5000)
Declare @searhString VARCHAR(250)

set  @searhString='firstweek'

declare db_cursor cursor for 
select dbid, [name] 
from master..sysdatabases
where [name] not in ('master', 'model', 'msdb', 'tempdb', 'northwind', 'pubs')



open db_cursor
fetch next from db_cursor into @dbid, @dbname

while (@@fetch_status = 0)
begin
    PRINT 'DB='+@dbname
    set @longstr = 'Use ' + @dbname + char(13) +        
        'insert into #temp1 ' + char(13) +  
        'SELECT @@ServerName,  ''' + @dbname + ''', Name 
        , case  when [Type]= ''P'' Then ''Procedure''
                when[Type]= ''V'' Then ''View''
                when [Type]=  ''TF'' Then ''Table-Valued Function'' 
                when [Type]=  ''FN'' Then ''Function'' 
                when [Type]=  ''TR'' Then ''Trigger'' 
                else [Type]/*''Others''*/
                end 
        , '''+ @searhString +''' FROM  [SYS].[SYSCOMMEnTS]
        JOIN  [SYS].objects ON ID = object_id
        WHERE TEXT LIKE ''%' + @searhString + '%'''

 exec (@longstr)
 fetch next from db_cursor into @dbid, @dbname
end

close db_cursor
deallocate db_cursor
select * from #temp1
Drop table #temp1

【讨论】:

【参考方案9】:

我用这个来工作。虽然在@TEXT 字段中去掉[],但似乎想要返回所有内容......

设置无计数 声明 @TEXT VARCHAR(250) 声明 @SQL VARCHAR(250) 选择 @TEXT='10.10.100.50' CREATE TABLE #results (db VARCHAR(64), objectname VARCHAR(100),xtype VARCHAR(10), definition TEXT) 选择 @TEXT 作为“搜索字符串” DECLARE #databases CURSOR FOR SELECT NAME FROM master..sysdatabases where dbid>4 声明 @c_dbname varchar(64) 打开#databases FETCH #databases INTO @c_dbname 而@@FETCH_STATUS -1 开始 SELECT @SQL = '插入 #results ' SELECT @SQL = @SQL + 'SELECT ''' + @c_dbname + ''' AS db, o.name,o.xtype,m.definition ' SELECT @SQL = @SQL + ' FROM '+@c_dbname+'.sys.sql_modules m ' SELECT @SQL = @SQL + 'INNER JOIN '+@c_dbname+'..sysobjects o ON m.object_id=o.id' SELECT @SQL = @SQL + ' WHERE [定义] LIKE ''%'+@TEXT+'%''' 执行(@SQL) FETCH #databases INTO @c_dbname 结尾 关闭#数据库 DEALLOCATE #databases SELECT * FROM #results order by db, xtype, objectname 删除表#results

【讨论】:

【参考方案10】:

我过去用过这些:

Searching all user stored procedures for a table name Search and replace SQL Server data in all columns of all tables

在这种特殊情况下,您需要跨存储过程替换特定字符串,第一个链接可能更相关。

有点离题,Quick Find add-in 对于使用 SQL Server Management Studio 搜索对象名称也很有用。有一个 modified version 提供了一些改进,另一个 newer version 在 Codeplex 上也提供了一些其他有用的插件。

【讨论】:

【参考方案11】:

使用 select 语句进行的任何搜索都只会产生对象名称,其中搜索关键字包含。 最简单有效的方法是获取过程/函数的脚本,然后在生成的文本文件中搜索,我也遵循这种技术:) 所以你很准确。

【讨论】:

【参考方案12】:

您可以使用以下 SQL 在所有数据库对象的定义中进行搜索:

SELECT 
    o.name, 
    o.id, 
    c.text,
    o.type
FROM 
    sysobjects o 
RIGHT JOIN syscomments c 
    ON o.id = c.id 
WHERE 
    c.text like '%text_to_find%'

【讨论】:

【参考方案13】:
SELECT ROUTINE_TYPE, ROUTINE_NAME, ROUTINE_DEFINITION
FROM INFORMATION_SCHEMA.ROUTINES 
WHERE ROUTINE_DEFINITION LIKE '%Your Text%' 

【讨论】:

【参考方案14】:

刚刚为通用的完整外部交叉参考写了这个

create table #XRefDBs(xtype varchar(2),SourceDB varchar(100), Object varchar(100), RefDB varchar(100))

declare @sourcedbname varchar(100),
        @searchfordbname varchar(100),
        @sql nvarchar(4000)
declare curs cursor for
    select name 
    from sysdatabases
    where dbid>4
open curs
fetch next from curs into @sourcedbname
while @@fetch_status=0
    begin
    print @sourcedbname
    declare curs2 cursor for 
        select name 
        from sysdatabases
        where dbid>4
        and name <> @sourcedbname
    open curs2
    fetch next from curs2 into @searchfordbname
    while @@fetch_status=0
        begin
        print @searchfordbname
        set @sql = 
        'INSERT INTO #XRefDBs (xtype,SourceDB,Object, RefDB)
        select DISTINCT o.xtype,'''+@sourcedbname+''', o.name,'''+@searchfordbname+'''
        from '+@sourcedbname+'.dbo.syscomments c
        join '+@sourcedbname+'.dbo.sysobjects o on c.id=o.id
        where o.xtype in (''V'',''P'',''FN'',''TR'')
        and (text like ''%'+@searchfordbname+'.%''
          or text like ''%'+@searchfordbname+'].%'')'
        print @sql
        exec sp_executesql @sql
        fetch next from curs2 into @searchfordbname
        end
    close curs2
    deallocate curs2
    fetch next from curs into @sourcedbname
    end
close curs
deallocate curs

select * from #XRefDBs

【讨论】:

以上是关于如何在 SQL Server 过程/触发器中查找文本?的主要内容,如果未能解决你的问题,请参考以下文章

遍历SQL SERVER中所有存储过程和触发器

如何在 SQL Server 中查找使用“我的数据库”的存储过程

SQL Server T—SQL 存储过程 触发器

确定用户在 SQL Server 中创建的对象

SQL Server 存储过程和触发器

批量删除Sql Server对象(表,存储过程,触发器)