Comment trouver un texte dans les procédures / déclencheurs SQL Server?

173

J'ai un serveur lié qui va changer. Certaines procédures appellent le serveur lié comme ceci: [10.10.100.50].dbo.SPROCEDURE_EXAMPLE. Nous avons également des déclencheurs qui font ce genre de travail. Nous devons trouver tous les endroits qui servent [10.10.100.50]à le changer.

Dans SQL Server Management Studio Express, je n'ai pas trouvé de fonctionnalité comme «rechercher dans toute la base de données» dans Visual Studio. Une sélection système spéciale peut-elle m'aider à trouver ce dont j'ai besoin?

Victor Rodrigues
la source

Réponses:

310

voici une partie d'une procédure que j'utilise sur mon système pour trouver du texte ...

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.
la source
1
De plus, vous pouvez l'ajouter à votre jeu de résultats pour voir rapidement le texte qui contient la valeur que vous recherchez. , substring (m.definition, charindex (@Search, m.definition), 100)
Chris Rodriguez
2
@ChrisRodriguez, bonne idée, mais rappelez-vous que ce ne sera que la première correspondance parmi plusieurs d'entre elles dans chaque procédure / déclencheur / fonction
KM.
Non valide pour les contraintes ( type = 'C')?
Kiquenet
18

Vous pouvez le trouver comme

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

Il répertorie les noms de procédure stockée distincts qui contiennent du texte comme «Utilisateur» dans la procédure stockée. Plus d'informations

ashish.chotalia
la source
8
Sachez simplement que la syscommentstable stocke les valeurs dans des blocs de 8000 caractères, donc si vous avez la malchance de diviser le texte que vous recherchez à travers l'une de ces limites, vous ne le trouverez pas avec cette méthode.
ErikE
17

[Réponse tardive mais, espérons-le, utile]

L'utilisation de tables système ne donne pas toujours des résultats corrects à 100% car il se peut que certaines procédures stockées et / ou vues soient cryptées, auquel cas vous devrez utiliser une connexion DAC pour obtenir les données dont vous avez besoin.

Je recommanderais d'utiliser un outil tiers tel que ApexSQL Search qui peut traiter facilement les objets cryptés.

La table système Syscomments donnera une valeur nulle pour la colonne de texte au cas où l'objet est chiffré.

Dwoolk
la source
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
la source
1
Cela n'inclut pas les déclencheurs comme la question posée
Enkode
Valable pour les vues, les procédures stockées, les tables définies par l'utilisateur ? et pour les déclencheurs, les fonctions, les contraintes, les règles, les valeurs par défaut ?
Kiquenet
5

Cela fonctionnera pour vous:

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
la source
Non valide pour les contraintes ( type = 'C')?
Kiquenet
4

Il existe de bien meilleures solutions que de modifier le texte de vos procédures stockées, fonctions et vues chaque fois que le serveur lié change. Voici quelques options:

  1. Mettez à jour le serveur lié. Au lieu d'utiliser un serveur lié nommé avec son adresse IP, créez un nouveau serveur lié avec le nom de la ressource tel que Financeou DataLinkProdou un autre. Ensuite, lorsque vous devez changer le serveur atteint, mettez à jour le serveur lié pour qu'il pointe vers le nouveau serveur (ou supprimez-le et recréez-le).

  2. Bien que vous ne puissiez malheureusement pas créer de synonymes pour des serveurs ou des schémas liés, vous POUVEZ créer des synonymes pour des objets situés sur des serveurs liés. Par exemple, votre procédure [10.10.100.50].dbo.SPROCEDURE_EXAMPLEpourrait être aliasée. Créez peut-être un schéma datalinkprod, alors CREATE SYNONYM datalinkprod.dbo_SPROCEDURE_EXAMPLE FOR [10.10.100.50].dbo.SPROCEDURE_EXAMPLE;. Ensuite, écrivez une procédure stockée qui accepte un nom de serveur lié, qui interroge tous les objets potentiels de la base de données distante et (re) crée des synonymes pour eux. Tous vos SP et fonctions sont réécrits une seule fois pour utiliser les noms de synonymes en commençant par datalinkprod, et par la suite, pour passer d'un serveur lié à un autre que vous venez de faire EXEC dbo.SwitchLinkedServer '[10.10.100.51]';et en une fraction de seconde, vous utilisez un serveur lié différent.

Il peut y avoir encore plus d'options. Je recommande fortement d'utiliser les techniques supérieures de prétraitement, de configuration ou d'indirection plutôt que de modifier les scripts écrits par l'homme. La mise à jour automatique des scripts créés par la machine est très bien, il s'agit d'un prétraitement. Faire les choses manuellement est horrible.

ErikE
la source
Je suis d'accord avec votre suggestion. Mais dans une situation comme celle décrite par l'OP, vous devez toujours trouver toutes les procédures stockées contenant l'adresse IP du serveur. Et même si vous ne devez le faire qu'une seule fois, le faire à la main peut être beaucoup de travail.
Paul Groke
@PaulGroke Oui, ce "beaucoup" de travail est la dette technique causée par de mauvais choix techniques dans le système enraciné. Il faut du temps pour s'en remettre - rembourser la dette accumulée. Mais ma suggestion est de savoir comment créer de la richesse technique - passer plus de temps maintenant pour être plus rapide, plus agile et plus fiable plus tard. Lisez l'article Big Ball of Mud pour quelques idées à ce sujet.
ErikE le
Ce que je voulais dire, c'est: qu'est-ce qui ne va pas en réduisant ce travail de «remboursement de la dette» en utilisant l'une des instructions SELECT que d'autres ont publiées ici?
Paul Groke
@PaulGroke Il n'y a rien de mal à trouver un moyen rapide de trouver des objets pouvant faire référence au serveur lié. Mais vous connaissez ce vieil adage sur "apprendre à un homme à pêcher" plutôt que "donner un poisson à un homme"? Ouais. Cette chose.
ErikE
@ErikE Thing est - vous ne lui apprenez pas à pêcher, vous dites simplement que s'il pêche, il peut obtenir de la nourriture. Votre réponse est un excellent conseil, mais n'aide pas le PO à le mettre en œuvre. Ajouter un moyen de trouver ces références afin que vous puissiez les remplacer par quelque chose de mieux conçu rendrait cette réponse bien meilleure.
T. Sar
2
select text
from syscomments
where text like '%your text here%'
Rez.Net
la source
2

Celui-ci que j'ai essayé dans SQL2008, qui peut rechercher dans toute la base de données en une fois.

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
la source
0

J'utilise celui-ci pour le travail. laissez les [] dans le champ @TEXT, semble vouloir tout renvoyer ...

SET NOCOUNT ON

DÉCLARER @TEXT VARCHAR (250)
DÉCLARER @SQL VARCHAR (250)

SELECT @ TEXT = '10 .10.100.50 '

CREATE TABLE #results (db VARCHAR (64), nom d'objet VARCHAR (100), xtype VARCHAR (10), définition TEXT)

SELECT @TEXT comme 'Chaîne de recherche'
DECLARE #databases CURSEUR POUR SELECT NAME FROM master..sysdatabases où dbid> 4
    DÉCLARER @c_dbname varchar (64)   
    OUVRIR #databases
    FETCH #databases INTO @c_dbname   
    WHILE @@ FETCH_STATUS -1
    COMMENCER
        SELECT @SQL = 'INSÉRER DANS #résultats'
        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 [définition] LIKE' '%' + @ TEXT + '%' ''   
        EXEC (@SQL)
        FETCH #databases INTO @c_dbname
    FIN
    CLOSE #databases
DEALLOCATE #databases

SELECT * FROM #results order by db, xtype, objectname
DROP TABLE #résultats
Christopher Klein
la source
0

J'ai utilisé ces derniers dans le passé:

Dans ce cas particulier, où vous devez remplacer une chaîne spécifique dans les procédures stockées, le premier lien est probablement plus pertinent.

Un peu hors sujet, le complément de recherche rapide est également utile pour rechercher des noms d'objets avec SQL Server Management Studio. Une version modifiée est disponible avec quelques améliorations, et une autre version plus récente est également disponible sur Codeplex avec d'autres compléments utiles également.

Mun
la source
0

Toute recherche avec l'instruction SELECT ne vous donne que le nom de l'objet, où le mot clé de recherche contient. Le moyen le plus simple et efficace est d'obtenir le script de la procédure / fonction, puis de rechercher dans le fichier texte généré, je suit également cette technique :) Donc, vous êtes exact.

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

Je viens d'écrire ceci pour la référence croisée externe complète générique

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
la source
-1

Vous pouvez rechercher dans les définitions de tous les objets de base de données à l'aide du SQL suivant:

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
la source