Come trovare un testo all'interno delle procedure / trigger di SQL Server?


173

Ho un linkedserver che cambierà. Alcune procedure chiamano il server collegato in questo modo: [10.10.100.50].dbo.SPROCEDURE_EXAMPLE. Abbiamo anche dei trigger che fanno questo tipo di lavoro. Dobbiamo trovare tutti i luoghi che usano [10.10.100.50]per cambiarlo.

In SQL Server Management Studio Express, non ho trovato una funzionalità come "trova nell'intero database" in Visual Studio. Una selezione speciale di sistema può aiutarmi a trovare ciò di cui ho bisogno?

Risposte:


310

ecco una parte di una procedura che uso sul mio sistema per trovare testo ....

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
Inoltre puoi aggiungere questo al tuo gruppo di risultati per vedere rapidamente il testo che contiene il valore che stai cercando. , sottostringa (m.definition, charindex (@Search, m.definition), 100)
Chris Rodriguez,

2
@ChrisRodriguez, buona idea, ma ricorda che sarà solo la prima partita di forse molti all'interno di ogni procedura / trigger / funzione
KM.

Non valido per Vincoli ( type = 'C')?
Kiquenet,

18

Puoi trovarlo come

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

Elencherà nomi distinti di stored procedure che contengono testo come "Utente" all'interno della stored procedure. Ulteriori informazioni


8
Basta essere consapevoli del fatto che la syscommentstabella memorizza i valori in blocchi di 8000 caratteri, quindi se si è abbastanza sfortunati da avere il testo che si sta cercando di dividere su uno di questi confini, non lo si troverà con questo metodo.
ErikE

17

[Risposta tardiva ma si spera utile]

L'uso delle tabelle di sistema non fornisce sempre risultati corretti al 100% perché potrebbe esserci la possibilità che alcune procedure e / o viste memorizzate siano crittografate, nel qual caso sarà necessario utilizzare la connessione DAC per ottenere i dati necessari.

Consiglio di utilizzare uno strumento di terze parti come ApexSQL Search in grado di gestire facilmente oggetti crittografati.

La tabella di sistema dei sistemi fornirà un valore nullo per la colonna di testo nel caso in cui l'oggetto sia crittografato.


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
Ciò non include trigger come la domanda posta
Enkode

Valido per visualizzazioni, stored procedure, tabelle definite dall'utente ? e per trigger, funzioni, vincoli, regole, valori predefiniti ?
Kiquenet,

5

Questo funzionerà per te:

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

Non valido per Vincoli ( type = 'C')?
Kiquenet,

4

Esistono soluzioni molto migliori rispetto alla modifica del testo delle procedure, delle funzioni e delle viste archiviate ogni volta che cambia il server collegato. Ecco alcune opzioni:

  1. Aggiorna il server collegato. Invece di utilizzare un server collegato denominato con il suo indirizzo IP, creare un nuovo server collegato con il nome della risorsa come Financeo DataLinkProdo alcuni di questi. Quindi, quando è necessario modificare il server raggiunto, aggiornare il server collegato per puntare al nuovo server (oppure rilasciarlo e ricrearlo).

  2. Mentre sfortunatamente non è possibile creare sinonimi per server o schemi collegati, è possibile creare sinonimi per oggetti che si trovano su server collegati. Ad esempio, la procedura [10.10.100.50].dbo.SPROCEDURE_EXAMPLEpotrebbe essere aliasata. Forse creare uno schema datalinkprod, quindi CREATE SYNONYM datalinkprod.dbo_SPROCEDURE_EXAMPLE FOR [10.10.100.50].dbo.SPROCEDURE_EXAMPLE;. Quindi, scrivere una procedura memorizzata che accetta un nome di server collegato, che interroga tutti i potenziali oggetti dal database remoto e (ri) crea sinonimi per essi. Tutti i tuoi SP e funzioni vengono riscritti solo una volta per usare i nomi dei sinonimi datalinkprodsin dall'inizio, e sempre dopo, per passare da un server collegato a un altro che fai EXEC dbo.SwitchLinkedServer '[10.10.100.51]';e in una frazione di secondo stai usando un altro server collegato.

Potrebbero esserci ancora più opzioni. Consiglio vivamente di usare le tecniche superiori di pre-elaborazione, configurazione o indiretta piuttosto che cambiare gli script scritti dall'uomo. L'aggiornamento automatico degli script creati dalla macchina va bene, questo è preelaborazione. Fare le cose manualmente è terribile.


Sono d'accordo con il tuo suggerimento. Ma in una situazione come quella descritta dall'OP, è ancora necessario trovare tutte le procedure memorizzate che contengono l'IP del server. E anche se lo devi fare solo una volta, farlo a mano potrebbe richiedere molto lavoro.
Paul Groke,

@PaulGroke Sì, questo "molto" lavoro è il debito tecnico causato da scarse scelte tecniche nel sistema radicato. Ci vuole tempo per riprendersi, ripagando il debito maturato. Ma il mio suggerimento è come creare ricchezza tecnica, passare più tempo ora per essere più veloce, più agile e più affidabile in seguito. Leggi l'articolo Big Ball of Mud per alcune idee in merito.
ErikE

Quello che volevo dire era: cosa c'è di sbagliato riducendo quel lavoro di "pagamento dei debiti" usando una delle dichiarazioni SELECT che altri hanno pubblicato qui?
Paul Groke,

@PaulGroke Non c'è niente di sbagliato in un modo rapido per trovare oggetti che potrebbero riferirsi al server collegato. Ma sai quel vecchio adagio su "insegnare a un uomo a pescare" piuttosto che "dare a un uomo un pesce"? Si. Quella cosa.
ErikE

@ErikE Il fatto è che non gli stai insegnando a pescare, ma stai solo dicendo che se pesca, può ottenere del cibo. La tua risposta è un ottimo consiglio, ma non aiuta l'OP a implementarla realmente. L'aggiunta di un modo per trovare quei riferimenti in modo da poterli sostituire con qualcosa di meglio progettato renderebbe questa risposta molto migliore.
T. Sar,

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

2

Questo ho provato in SQL2008, che può cercare da tutti i db in una volta sola.

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

Lo uso per lavoro. lasciare [] nel campo @TEXT, sembra voler restituire tutto ...

SET NOCOUNT ON

DECLARE @TEXT VARCHAR (250)
DECLARE @SQL VARCHAR (250)

SELECT @ TEXT = '10 .10.100.50 '

CREATE TABLE #results (db VARCHAR (64), nome oggetto VARCHAR (100), xtype VARCHAR (10), definizione TEXT)

SELEZIONA @TEXT come 'Stringa di ricerca'
DECLARE #database CURSORE PER SELEZIONA NOME DA master..sysdatabase dove dbid> 4
    DECLARE @c_dbname varchar (64)   
    # Database aperti
    FETCH #database INTO @c_dbname   
    WHILE @@ FETCH_STATUS -1
    INIZIO
        SELECT @SQL = 'INSERT INTO #results'
        SELECT @SQL = @SQL + 'SELECT' '' + @c_dbname + '' 'AS db, o.name, o.xtype, m.definition'   
        SELEZIONA @SQL = @SQL + 'FROM'+@c_dbname+'.sys.sql_modules m'   
        SELEZIONA @SQL = @SQL + 'INNER JOIN' + @ c_dbname + '.. sysobjects o ON m.object_id = o.id'   
        SELEZIONA @SQL = @SQL + 'WHERE [definition] LIKE' '%' + @ TEXT + '%' ''   
        EXEC (@SQL)
        FETCH #database INTO @c_dbname
    FINE
    CHIUDI #database
DEALLOCATE #database

SELEZIONA * DA # risultati ordinati per db, xtype, nome oggetto
DROP TABLE #results

0

Ho usato questi in passato:

In questo caso particolare, in cui è necessario sostituire una stringa specifica tra procedure memorizzate, il primo collegamento è probabilmente più pertinente.

Un po 'fuori tema, il componente aggiuntivo Ricerca rapida è utile anche per la ricerca di nomi di oggetti con SQL Server Management Studio. C'è una versione modificata disponibile con alcuni miglioramenti e un'altra versione più recente disponibile anche su Codeplex con alcuni altri componenti aggiuntivi utili.


0

Qualsiasi ricerca con istruzione select ti dà solo il nome dell'oggetto, dove contiene la parola chiave search. Il modo più semplice ed efficace è ottenere lo script della procedura / funzione e quindi cercare nel file di testo generato, seguo anche questa tecnica :) Quindi sei preciso.


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

0

Ho appena scritto questo per riferimento incrociato esterno completo generico

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

È possibile cercare all'interno delle definizioni di tutti gli oggetti del database usando il seguente 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%'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.