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


173

我有一个将更改的链接服务器。一些过程像这样调用链接服务器:[10.10.100.50].dbo.SPROCEDURE_EXAMPLE。我们也有触发器在做这种工作。我们需要找到所有[10.10.100.50]用于更改它的地方。

在SQL Server Management Studio Express中,我没有在Visual Studio中找到诸如“在整个数据库中查找”之类的功能。特殊的系统选择可以帮助我找到所需的东西吗?

Answers:


309

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

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

1
另外,您可以将其添加到结果集中以快速查看包含您要搜索的值的文本。,substring(m.definition,charindex(@Search,m.definition),100)
Chris Rodriguez

2
@ChrisRodriguez,好主意,但请记住,这只会是每个过程/触发器/功能
KM)中

约束type = 'C')无效吗?
Kiquenet '16

18

你可以找到它像

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

它将列出不同的存储过程名称,其中包含诸如“ User”之类的文本。更多信息


8
请注意,该syscomments表将值存储在8000个字符的块中,因此,如果您很不幸地将要搜索的文本划分为这些边界之一,则无法使用此方法找到它。
ErikE

17

[最新答案,但希望有用]

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

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

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


11
-- 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');

1
这不包括触发类似问题的触发器
Enkode

视图,存储过程,用户定义表有效吗?对于触发器,函数,约束,规则,默认值
Kiquenet '16

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')无效吗?
Kiquenet '16

4

多少不是修改你的存储过程,函数的文本更好的解决方案,并查看每次链接服务器的变化。以下是一些选项:

  1. 更新链接的服务器。不要使用以其IP地址命名的链接服务器,而是使用资源名称(例如Finance或诸如此类)创建一个新的链接服务器DataLinkProd。然后,当您需要更改到达哪个服务器时,更新链接的服务器以指向新服务器(或删除它并重新创建它)。

  2. 不幸的是,您不能为链接服务器或模式创建同义词,但可以为链接服务器上的对象创建同义词。例如,您的过程[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是的,这项“大量”工作是由根深蒂固的系统中技术选择不当造成的技术债务。从中恢复需要花费时间-还清应计债务。但是我的建议是如何建立技术财富-现在花更多的时间来更快,更敏捷,更可靠。阅读文章“泥浆大球”,了解有关此问题的一些想法。
ErikE

我的意思是:通过使用其他人在此处发布的SELECT语句来减少“还清债务”的工作有什么问题?
Paul Groke

@PaulGroke快速找到可以引用链接服务器的对象的方法没有什么问题。但是您知道那句古老的格言是“教人钓鱼”而不是“给人鱼”吗?是的 那个东西。
ErikE

@ErikE事情是-您不是在教他如何钓鱼,只是说如果他钓鱼,他就能得到食物。您的答案是很好的建议,但并不能帮助OP真正实现它。添加查找这些引用的方法,以便您可以用更好的设计替换它们,这将使此答案更好。
T. Sar,

2
select text
from syscomments
where text like '%your text here%'

2

我在SQL2008中尝试过这一功能,它可以一次从所有数据库中进行搜索。

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

0

我用这个工作。尽管在@TEXT字段中省略了[],但似乎想返回所有内容...

开启NOCOUNT

十进制@TEXT VARCHAR(250)
十进制@SQL VARCHAR(250)

SELECT @ TEXT = '10 .10.100.50'

创建表#结果(db VARCHAR(64),对象名VARCHAR(100),xtype VARCHAR(10),定义TEXT)

选择@TEXT作为“搜索字符串”
DECLARE #databases从master..sysdatabases中选择名称的游标,其中dbid> 4
    宣告@c_dbname varchar(64)   
    OPEN#数据库
    FETCH#数据库INTO @c_dbname   
    @@ FETCH_STATUS -1时
    开始
        SELECT @SQL ='将结果插入#results'
        SELECT @SQL = @SQL +'SELECT'''+ @c_dbname +'''AS db,o.name,o.xtype,m.definition'   
        选择@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 [定义]就像``%'+ @ TEXT +'%'''   
        执行(@SQL)
        FETCH#数据库INTO @c_dbname
    结束
    关闭#数据库
取消分配数据库

SELECT * FROM#按数据库,xtype,对象名的结果顺序
删除表#结果

0

我过去曾经使用过这些:

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

有点偏离主题的快速查找加载项对于使用SQL Server Management Studio搜索对象名称也很有用。有个经过改进的改进版本,另外一个较新的版本在Codeplex上也提供了一些其他有用的加载项。


0

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


0
SELECT ROUTINE_TYPE, ROUTINE_NAME, ROUTINE_DEFINITION
FROM INFORMATION_SCHEMA.ROUTINES 
WHERE ROUTINE_DEFINITION LIKE '%Your Text%' 

0

刚刚为通用完整外部交叉引用编写了此代码

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

-1

您可以使用以下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%'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.