Wie finde ich einen Text in SQL Server-Prozeduren / -Triggern?


173

Ich habe einen Linkserver, der sich ändern wird. Einige Verfahren rufen den Verbindungsserver folgendermaßen auf : [10.10.100.50].dbo.SPROCEDURE_EXAMPLE. Wir haben Auslöser, die auch diese Art von Arbeit erledigen. Wir müssen alle Orte finden, [10.10.100.50]an denen sich etwas ändert.

In SQL Server Management Studio Express habe ich in Visual Studio keine Funktion wie "In der gesamten Datenbank suchen" gefunden. Kann mir eine spezielle Systemauswahl helfen, das zu finden, was ich brauche?

Antworten:


310

Hier ist ein Teil einer Prozedur, die ich auf meinem System verwende, um Text zu finden.

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
Darüber hinaus können Sie dies zu Ihrer Ergebnismenge hinzufügen, um schnell den Text anzuzeigen, der den Wert enthält, nach dem Sie suchen. , Teilzeichenfolge (m.definition, charindex (@Search, m.definition), 100)
Chris Rodriguez

2
@ ChrisRodriguez, gute Idee, aber denken Sie daran, dass dies nur die erste Übereinstimmung von möglicherweise vielen innerhalb jeder Prozedur / Trigger / Funktion sein wird
KM.

Nicht gültig für Constraints ( type = 'C')?
Kiquenet

18

Sie können es wie finden

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

Es werden verschiedene Namen gespeicherter Prozeduren aufgelistet, die Text wie 'Benutzer' in der gespeicherten Prozedur enthalten. Mehr Info


8
Beachten Sie jedoch, dass die syscommentsTabelle die Werte in Blöcken mit 8000 Zeichen speichert. Wenn Sie also das Pech haben, den gesuchten Text über eine dieser Grenzen zu verteilen, werden Sie ihn mit dieser Methode nicht finden.
ErikE

17

[Späte Antwort, aber hoffentlich nützlich]

Die Verwendung von Systemtabellen führt nicht immer zu 100% korrekten Ergebnissen, da möglicherweise einige gespeicherte Prozeduren und / oder Ansichten verschlüsselt sind. In diesem Fall müssen Sie eine DAC- Verbindung verwenden, um die benötigten Daten abzurufen.

Ich würde empfehlen, ein Drittanbieter-Tool wie ApexSQL Search zu verwenden , mit dem verschlüsselte Objekte problemlos verarbeitet werden können.

Die Syscomments-Systemtabelle gibt den Nullwert für die Textspalte an, falls das Objekt verschlüsselt ist.


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
Dies beinhaltet keine Auslöser wie die gestellte Frage
Enkode

Gültig für Ansichten, gespeicherte Prozeduren, benutzerdefinierte Tabellen ? und für Trigger, Funktionen, Einschränkungen, Regeln, Standardeinstellungen ?
Kiquenet

5

Dies wird für Sie funktionieren:

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

Nicht gültig für Constraints ( type = 'C')?
Kiquenet

4

Es gibt viel bessere Lösungen, als den Text Ihrer gespeicherten Prozeduren, Funktionen und Ansichten jedes Mal zu ändern, wenn sich der Verbindungsserver ändert. Hier sind einige Optionen:

  1. Aktualisieren Sie den Verbindungsserver. Anstatt einen Verbindungsserver mit seiner IP-Adresse zu verwenden, erstellen Sie einen neuen Verbindungsserver mit dem Namen der Ressource wie Financeoder DataLinkPrododer einem solchen. Wenn Sie dann ändern müssen, welcher Server erreicht wird, aktualisieren Sie den Verbindungsserver so, dass er auf den neuen Server verweist (oder löschen Sie ihn und erstellen Sie ihn neu).

  2. Während Sie leider keine Synonyme für Verbindungsserver oder Schemas erstellen können, können Sie Synonyme für Objekte erstellen, die sich auf Verbindungsservern befinden. Zum Beispiel [10.10.100.50].dbo.SPROCEDURE_EXAMPLEkönnte Ihre Prozedur einen Alias ​​haben. Vielleicht ein Schema erstellen datalinkprod, dann CREATE SYNONYM datalinkprod.dbo_SPROCEDURE_EXAMPLE FOR [10.10.100.50].dbo.SPROCEDURE_EXAMPLE;. Schreiben Sie dann eine gespeicherte Prozedur, die einen Verbindungsservernamen akzeptiert, der alle potenziellen Objekte aus der entfernten Datenbank abfragt und Synonyme für sie (neu) erstellt. Alle Ihre SPs und Funktionen werden nur einmal neu geschrieben, um die Synonymnamen zu verwenden, beginnend mit datalinkprodund danach, um von einem Verbindungsserver auf einen anderen zu wechseln, EXEC dbo.SwitchLinkedServer '[10.10.100.51]';und in Sekundenbruchteilen verwenden Sie einen anderen Verbindungsserver.

Möglicherweise gibt es noch mehr Optionen. Ich empfehle dringend, die überlegenen Techniken der Vorverarbeitung, Konfiguration oder Indirektion zu verwenden, anstatt von Menschen geschriebene Skripte zu ändern. Das automatische Aktualisieren von maschinell erstellten Skripten ist in Ordnung. Dies ist eine Vorverarbeitung. Dinge manuell zu machen ist schrecklich.


Ich stimme Ihrem Vorschlag zu. In einer Situation wie der im OP beschriebenen müssen Sie jedoch immer noch alle gespeicherten Prozeduren finden, die die Server-IP enthalten. Und selbst wenn Sie es nur einmal tun müssen, kann es eine Menge Arbeit sein , es von Hand zu tun .
Paul Groke

@PaulGroke Ja, diese "Menge" Arbeit ist die technische Verschuldung, die durch schlechte technische Entscheidungen im fest verankerten System verursacht wird. Es braucht Zeit, um sich davon zu erholen - die aufgelaufenen Schulden abzuzahlen. Mein Vorschlag ist jedoch, wie man technischen Wohlstand schafft - jetzt mehr Zeit zu verbringen, um später schneller, agiler und zuverlässiger zu werden. Lesen Sie den Artikel Big Ball of Mud, um einige Ideen dazu zu erhalten.
ErikE

Was ich damit meinte war: Was ist falsch daran, diese "Schuldentilgung" durch die Verwendung einer der SELECT-Anweisungen, die andere hier gepostet haben, zu reduzieren?
Paul Groke

@PaulGroke Es ist nichts Falsches daran, schnell nach Objekten zu suchen, die möglicherweise auf den Verbindungsserver verweisen. Aber wissen Sie, dass das alte Sprichwort "einem Mann das Fischen beibringen" statt "einem Mann einen Fisch geben"? Ja. Das Ding.
ErikE

@ErikE Die Sache ist - du bringst ihm nicht das Fischen bei, sondern sagst nur, dass er Essen bekommen kann, wenn er fischt. Ihre Antwort ist ein guter Rat, hilft dem OP jedoch nicht, ihn tatsächlich umzusetzen. Wenn Sie eine Möglichkeit hinzufügen, diese Referenzen zu finden, damit Sie sie durch etwas Besseres ersetzen können, wird diese Antwort viel besser.
T. Sar

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

2

Dieses habe ich in SQL2008 ausprobiert, das von allen Datenbanken auf einmal suchen kann.

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

Ich benutze diesen für die Arbeit. Lass die [] weg, obwohl im @ TEXT-Feld, scheint alles zurückgeben zu wollen ...

NOCOUNT EINSETZEN

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

SELECT @ TEXT = '10 .10.100.50 '

CREATE TABLE #results (db VARCHAR (64), Objektname VARCHAR (100), xtype VARCHAR (10), Definition TEXT)

SELECT @TEXT als 'Search String'
DECLARE #databases CURSOR FOR SELECT NAME FROM master..sysdatabases wobei dbid> 4
    DECLARE @c_dbname varchar (64)   
    OPEN #Datenbanken
    FETCH #databases INTO @c_dbname   
    WÄHREND @@ FETCH_STATUS -1
    START
        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 [Definition] LIKE' '%' + @ TEXT + '%' ''   
        EXEC (@SQL)
        FETCH #databases INTO @c_dbname
    ENDE
    #Datenbanken SCHLIESSEN
DEALLOCATE #databases

SELECT * FROM #Ergebnisreihenfolge nach Datenbank, XType, Objektname
DROP TABLE #Ergebnisse

0

Ich habe diese in der Vergangenheit verwendet:

In diesem speziellen Fall, in dem Sie eine bestimmte Zeichenfolge über gespeicherte Prozeduren hinweg ersetzen müssen, ist der erste Link wahrscheinlich relevanter.

Das Quick Find-Add-In ist ein wenig abseits des Themas und auch nützlich für die Suche nach Objektnamen mit SQL Server Management Studio. Es gibt eine modifizierte Version mit einigen Verbesserungen und eine andere neuere Version, die auch auf Codeplex verfügbar ist, mit einigen anderen nützlichen Add-Ins.


0

Bei jeder Suche mit der Anweisung select erhalten Sie nur den Objektnamen, in dem das Suchschlüsselwort enthalten ist. Der einfachste und effizienteste Weg ist, ein Skript für die Prozedur / Funktion zu erhalten und dann in der generierten Textdatei zu suchen. Ich folge auch dieser Technik :) Sie sind also genau punktgenau.


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

0

Ich habe dies gerade für die generische vollständige äußere Kreuzreferenz geschrieben

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

Sie können innerhalb der Definitionen aller Datenbankobjekte mit dem folgenden SQL suchen:

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%'
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.