Como encontrar um texto dentro dos procedimentos / gatilhos do SQL Server?

173

Eu tenho um servidor de links que mudará. Alguns procedimentos chamar o servidor vinculado como este: [10.10.100.50].dbo.SPROCEDURE_EXAMPLE. Temos gatilhos também fazendo esse tipo de trabalho. Precisamos encontrar todos os lugares usados [10.10.100.50]para alterá-lo.

No SQL Server Management Studio Express, não encontrei um recurso como "localizar no banco de dados inteiro" no Visual Studio. Um sys-select especial pode me ajudar a encontrar o que eu preciso?

Victor Rodrigues
fonte

Respostas:

310

aqui está uma parte de um procedimento que eu uso no meu sistema para encontrar texto ....

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
KM.
fonte
1
Além disso, você pode adicionar isso ao seu conjunto de resultados para ver rapidamente o texto que contém o valor que você está procurando. , substring (m.definition, charindex (@Search, m.definition), 100)
Chris Rodriguez
2
@ Chrishrodriguez, boa ideia, mas lembre-se de que será apenas a primeira partida de possivelmente muitos em cada procedimento / trigger / função
KM.
Não é válido para Restrições ( type = 'C')?
Kiquenet 12/08/16
18

Você pode achar isso como

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

Ele listará nomes distintos de procedimentos armazenados que contêm texto como 'Usuário' dentro do procedimento armazenado. Mais informações

ashish.chotalia
fonte
8
Lembre-se de que a syscommentstabela armazena os valores em blocos de 8.000 caracteres. Portanto, se você tiver a infelicidade de ter o texto que está procurando dividido em um desses limites, não o encontrará com esse método.
ErikE
17

[Resposta tardia, mas espero que útil]

O uso de tabelas do sistema nem sempre fornece resultados 100% corretos, pois pode haver a possibilidade de que alguns procedimentos e / ou visualizações armazenados sejam criptografados. Nesse caso, você precisará usar a conexão DAC para obter os dados necessários.

Eu recomendo o uso de uma ferramenta de terceiros, como o ApexSQL Search, que pode lidar com objetos criptografados facilmente.

A tabela do sistema Syscomments fornecerá um valor nulo para a coluna de texto, caso o objeto seja criptografado.

Dwoolk
fonte
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');
Heba Mahmoud
fonte
1
Isso não inclui os gatilhos como a pergunta
Enkode
Válido para visualizações, procedimentos armazenados, tabelas definidas pelo usuário ? e para gatilhos, funções, restrições, regras, padrões ?
Kiquenet 12/08/16
5

Isso funcionará para você:

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
Laurens
fonte
Não é válido para Restrições ( type = 'C')?
Kiquenet
4

Existem soluções muito melhores do que modificar o texto dos procedimentos, funções e visualizações armazenados cada vez que o servidor vinculado é alterado. Aqui estão algumas opções:

  1. Atualize o servidor vinculado. Em vez de usar um servidor vinculado nomeado com seu endereço IP, crie um novo servidor vinculado com o nome do recurso, como Financeou DataLinkProdou algum desses. Quando você precisar alterar qual servidor é atingido, atualize o servidor vinculado para apontar para o novo servidor (ou solte-o e recriá-lo).

  2. Embora, infelizmente, você não possa criar sinônimos para servidores ou esquemas vinculados, você PODE criar sinônimos para objetos localizados em servidores vinculados. Por exemplo, seu procedimento [10.10.100.50].dbo.SPROCEDURE_EXAMPLEpoderia ser alternativo. Talvez crie um esquema datalinkprod, então CREATE SYNONYM datalinkprod.dbo_SPROCEDURE_EXAMPLE FOR [10.10.100.50].dbo.SPROCEDURE_EXAMPLE;. Em seguida, escreva um procedimento armazenado que aceite um nome de servidor vinculado, que consulte todos os objetos em potencial do banco de dados remoto e (re) crie sinônimos para eles. Todos os seus SPs e funções são reescritos apenas uma vez para usar os nomes de sinônimos datalinkprod, e depois disso, para mudar de um servidor vinculado para outro, basta você fazer EXEC dbo.SwitchLinkedServer '[10.10.100.51]';e, em uma fração de segundo, usar um servidor vinculado diferente.

Pode haver ainda mais opções. Eu recomendo usar as técnicas superiores de pré-processamento, configuração ou indireção, em vez de alterar scripts escritos por humanos. A atualização automática de scripts criados por máquina é boa, é pré-processamento. Fazer as coisas manualmente é horrível.

ErikE
fonte
Eu concordo com a sua sugestão. Mas em uma situação como a descrita pelo OP, você ainda precisa encontrar todos os procedimentos armazenados que contêm o IP do servidor. E mesmo que você precise fazer apenas uma vez, fazê-lo manualmente pode dar muito trabalho.
Paul Groke
@PaulGroke Sim, esse "muito" trabalho é a dívida técnica causada por más escolhas técnicas no sistema entrincheirado. Leva tempo para se recuperar disso - pagando a dívida acumulada. Mas minha sugestão é como criar riqueza técnica - gastando mais tempo agora para ser mais rápido, mais ágil e mais confiável posteriormente. Leia o artigo Big Ball of Mud para algumas idéias sobre isso.
ErikE 05/09
O que eu quis dizer foi: O que há de errado em reduzir o trabalho de "pagar dívidas" usando uma das instruções SELECT que outras pessoas postaram aqui?
Paul Groke
@PaulGroke Não há nada errado com uma maneira rápida de encontrar objetos que possam se referir ao servidor vinculado. Mas você conhece aquele velho ditado sobre "ensinar um homem a pescar" em vez de "dar um peixe a um homem"? Sim. Aquela coisa.
ErikE
@ErikE A coisa é - você não está ensinando a ele como pescar, apenas dizendo que se ele pescar, ele pode obter comida. Sua resposta é um ótimo conselho, mas não ajuda o OP a implementá-lo. Adicionar uma maneira de encontrar essas referências para substituí-las por algo melhor projetado tornaria essa resposta muito melhor.
568 Sar Sar
2
select text
from syscomments
where text like '%your text here%'
Rez.Net
fonte
2

Este eu tentei no SQL2008, que pode pesquisar de todos os db de uma só vez.

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
yenfang chang
fonte
0

Eu uso este para o trabalho. deixe o [] 's no campo @TEXT, parece querer retornar tudo ...

DEFINIR NOCOUNT ON

DECLARAR @TEXT VARCHAR (250)
DECLARAR @SQL VARCHAR (250)

SELECT @ TEXT = '10 .10.100.50 '

CREATE TABLE #results (db VARCHAR (64), nome do objeto VARCHAR (100), xtype VARCHAR (10), definição TEXT)

SELECIONE @TEXT como 'String de Pesquisa'
DECLARAR # bancos de dados CURSOR PARA SELECIONAR NOME DO master..sysdatabases em que dbid> 4
    DECLARE @c_dbname varchar (64)   
    OPEN #databases
    FETCH #databases INTO @c_dbname   
    ENQUANTO @@ FETCH_STATUS -1
    INÍCIO
        SELECT @SQL = 'INSERT INTO #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 [definição] CURTIR' '%' + @ TEXT + '%' ''   
        EXEC (@SQL)
        FETCH #databases INTO @c_dbname
    FIM
    CLOSE #databases
DEALLOCATE #databases

SELECT * FROM #results ordena por db, xtype, objectname
DROP TABLE #resultados
Christopher Klein
fonte
0

Eu usei estes no passado:

Nesse caso específico, em que você precisa substituir uma sequência específica nos procedimentos armazenados, o primeiro link é provavelmente mais relevante.

Um pouco estranho, o suplemento Pesquisa rápida também é útil para pesquisar nomes de objetos com o SQL Server Management Studio. Há uma versão modificada disponível com algumas melhorias e outra versão mais recente também disponível no Codeplex com alguns outros suplementos úteis.

Mun
fonte
0

Qualquer pesquisa com a instrução select fornece apenas o nome do objeto, onde a palavra-chave de pesquisa contém. A maneira mais fácil e eficiente é obter o script do procedimento / função e, em seguida, procurar no arquivo de texto gerado, eu também sigo essa técnica :) Então você é o ponto exato.

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

Acabei de escrever isso para referência externa cruzada genérica completa

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
Leif Peterson
fonte
-1

Você pode pesquisar nas definições de todos os objetos de banco de dados usando o seguinte 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%'
Joaquinglezsantos
fonte