¿Cómo encontrar un texto dentro de los procedimientos / disparadores de SQL Server?


173

Tengo un servidor de enlaces que cambiará. Algunos procedimientos llaman el servidor vinculado como esto: [10.10.100.50].dbo.SPROCEDURE_EXAMPLE. Tenemos disparadores que también hacen este tipo de trabajo. Necesitamos encontrar todos los lugares que usa [10.10.100.50]para cambiarlo.

En SQL Server Management Studio Express, no encontré una función como "buscar en toda la base de datos" en Visual Studio. ¿Puede un sys-select especial ayudarme a encontrar lo que necesito?

Respuestas:


310

Aquí hay una parte de un procedimiento que uso en mi sistema para buscar 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

1
Además, puede agregar esto a su conjunto de resultados para ver rápidamente el texto que contiene el valor que busca. , subcadena (m.definition, charindex (@Search, m.definition), 100)
Chris Rodriguez

2
@ChrisRodriguez, buena idea, pero recuerda que solo será la primera coincidencia de muchas posibles dentro de cada procedimiento / disparador / función
KM.

¿No es válido para restricciones ( type = 'C')?
Kiquenet

18

Puedes encontrarlo como

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

Enumerará distintos nombres de procedimientos almacenados que contienen texto como 'Usuario' dentro del procedimiento almacenado. Más información


8
Solo tenga en cuenta que la syscommentstabla almacena los valores en fragmentos de 8000 caracteres, por lo que si tiene la mala suerte de dividir el texto que está buscando en uno de estos límites, no lo encontrará con este método.
ErikE

17

[Respuesta tardía pero con suerte útil]

El uso de tablas del sistema no siempre proporciona resultados 100% correctos porque puede existir la posibilidad de que algunos procedimientos almacenados y / o vistas estén encriptados, en cuyo caso deberá usar la conexión DAC para obtener los datos que necesita.

Recomiendo usar una herramienta de terceros, como ApexSQL Search, que puede manejar objetos cifrados fácilmente.

La tabla del sistema Syscomments dará un valor nulo para la columna de texto en caso de que el objeto esté encriptado.


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
Esto no incluye desencadenantes como la pregunta formulada
Enkode

¿Válido para vistas, procedimientos almacenados, tablas definidas por el usuario ? y para disparadores, funciones, restricciones, reglas, valores predeterminados ?
Kiquenet

5

Esto funcionará para usted:

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

¿No es válido para restricciones ( type = 'C')?
Kiquenet

4

Hay soluciones mucho mejores que modificar el texto de sus procedimientos almacenados, funciones y vistas cada vez que cambia el servidor vinculado. Aquí hay algunas opciones:

  1. Actualiza el servidor vinculado. En lugar de utilizar un servidor vinculado llamado con su dirección IP, crear un nuevo servidor vinculado con el nombre del recurso, tales como Financeo DataLinkProd, o algo así. Luego, cuando necesite cambiar a qué servidor se llega, actualice el servidor vinculado para que apunte al nuevo servidor (o suéltelo y vuelva a crearlo).

  2. Aunque desafortunadamente no puede crear sinónimos para servidores o esquemas vinculados, PUEDE crear sinónimos para objetos ubicados en servidores vinculados. Por ejemplo, su procedimiento [10.10.100.50].dbo.SPROCEDURE_EXAMPLEpodría tener un alias. Quizás cree un esquema datalinkprod, entonces CREATE SYNONYM datalinkprod.dbo_SPROCEDURE_EXAMPLE FOR [10.10.100.50].dbo.SPROCEDURE_EXAMPLE;. Luego, escriba un procedimiento almacenado que acepte un nombre de servidor vinculado, que consulta todos los objetos potenciales de la base de datos remota y (re) crea sinónimos para ellos. Todos sus SP y funciones se reescriben solo una vez para usar los nombres de sinónimos que comienzan con datalinkprod, y después de eso, para cambiar de un servidor vinculado a otro, simplemente lo hace EXEC dbo.SwitchLinkedServer '[10.10.100.51]';y en una fracción de segundo está usando un servidor vinculado diferente.

Puede haber incluso más opciones. Recomiendo usar las técnicas superiores de preprocesamiento, configuración o indirección en lugar de cambiar los guiones escritos por humanos. La actualización automática de los scripts creados por la máquina está bien, esto es preprocesamiento. Hacer cosas manualmente es horrible.


Estoy de acuerdo con tu sugerencia Pero en una situación como la que describió el OP, aún necesita encontrar todos los procedimientos almacenados que contienen la IP del servidor. E incluso si solo tiene que hacerlo una vez, hacerlo a mano puede ser mucho trabajo.
Paul Groke

@PaulGroke Sí, este "mucho" trabajo es la deuda técnica causada por malas decisiones técnicas en el sistema arraigado. Se necesita tiempo para recuperarse de esto: pagar la deuda acumulada. Pero mi sugerencia es cómo construir riqueza técnica: pasar más tiempo ahora para ser más rápido, más ágil y más confiable más adelante. Lea el artículo Big Ball of Mud para obtener algunas ideas al respecto.
ErikE

Lo que quise decir fue: ¿Qué tiene de malo reducir ese trabajo de "pago de deudas" al usar una de las declaraciones SELECT que otros publicaron aquí?
Paul Groke

@PaulGroke No hay nada de malo en una forma rápida de encontrar objetos que puedan referirse al servidor vinculado. ¿Pero conoces ese viejo adagio sobre "enseñarle a un hombre a pescar" en lugar de "darle un pescado a un hombre"? Si. Esa cosa.
ErikE

@ErikE La cosa es que no le estás enseñando a pescar, solo dices que si pesca, puede conseguir comida. Su respuesta es un gran consejo, pero no ayuda al OP a implementarlo realmente. Agregar una forma de encontrar esas referencias para que pueda reemplazarlas con algo mejor diseñado haría que esta respuesta fuera mucho mejor.
T. Sar

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

2

Este lo probé en SQL2008, que puede buscar desde todos los db de una 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

0

Yo uso este para el trabajo. dejar fuera de [] 's aunque en el campo @TEXT, parece querer devolver todo ...

ESTABLECER CUENTA

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

SELECCIONAR @ TEXTO = '10 .10.100.50 '

CREATE TABLE #results (db VARCHAR (64), objectname VARCHAR (100), xtype VARCHAR (10), definición TEXT)

SELECCIONE @TEXT como 'Cadena de búsqueda'
DECLARAR #databases CURSOR PARA SELECCIONAR NOMBRE DE master..sysdatabases donde dbid> 4
    DECLARE @c_dbname varchar (64)   
    ABRIR #databases
    FETCH #databases INTO @c_dbname   
    MIENTRAS @@ FETCH_STATUS -1
    EMPEZAR
        SELECCIONE @SQL = 'INSERTAR EN #resultados'
        SELECT @SQL = @SQL + 'SELECT' '' + @c_dbname + '' 'AS db, o.name, o.xtype, m.definition'   
        SELECCIONE @SQL = @SQL + 'FROM'+@c_dbname+'.sys.sql_modules m'   
        SELECCIONE @SQL = @SQL + 'INNER JOIN' + @ c_dbname + '.. sysobjects o ON m.object_id = o.id'   
        SELECCIONE @SQL = @SQL + 'DONDE [definición] ME GUSTA' '%' + @ TEXT + '%' ''   
        EXEC (@SQL)
        FETCH #databases INTO @c_dbname
    FINAL
    CERRAR #databases
DEALLOCATE #databases

SELECCIONE * DE #resultados ordenados por db, xtype, objectname
TABLA DE GOTA #resultados

0

He usado estos en el pasado:

En este caso particular, donde necesita reemplazar una cadena específica en los procedimientos almacenados, el primer enlace probablemente sea más relevante.

Un poco fuera de tema, el complemento Búsqueda rápida también es útil para buscar nombres de objetos con SQL Server Management Studio. Hay una versión modificada disponible con algunas mejoras, y otra versión más nueva también disponible en Codeplex con algunos otros complementos útiles también.


0

Cualquier búsqueda con la instrucción select le proporciona solo el nombre del objeto, donde contiene la palabra clave de búsqueda. La manera más fácil y eficiente es obtener el script del procedimiento / función y luego buscar en el archivo de texto generado, también sigo esta técnica :) Así que eres exacto.


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

0

Acabo de escribir esto para la referencia cruzada externa 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

-1

Puede buscar dentro de las definiciones de todos los objetos de la base de datos utilizando el siguiente 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%'
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.