Как найти текст внутри процедур / триггеров SQL Server?


173

У меня есть связанный сервер, который изменится. Некоторые процедуры называют связанный сервер , как это: [10.10.100.50].dbo.SPROCEDURE_EXAMPLE. У нас есть триггеры, которые также выполняют эту работу. Нам нужно найти все места, которые используются [10.10.100.50]для его изменения.

В SQL Server Management Studio Express я не нашел такой функции, как «найти во всей базе данных» в Visual Studio. Может ли специальный sys-select помочь мне найти то, что мне нужно?

Ответы:


310

Вот часть процедуры, которую я использую в своей системе для поиска текста ....

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
Кроме того, вы можете добавить это в свой набор результатов, чтобы быстро увидеть текст, который содержит значение, которое вы ищете. , подстрока (m.definition, charindex (@Search, m.definition), 100)
Крис Родригес,

2
@ChrisRodriguez, хорошая идея, но помните, что это будет только первое совпадение, возможно, многих в каждой процедуре / триггере / функции
КМ.

Недействительно для ограничений ( type = 'C')?
Kiquenet

18

Вы можете найти это как

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

В нем будут перечислены различные имена хранимых процедур, которые содержат текст, такой как «Пользователь» внутри хранимой процедуры. Больше информации


8
Просто помните, что syscommentsтаблица хранит значения в виде фрагментов по 8000 символов, поэтому, если вам не повезло, что искомый текст разбит на одну из этих границ, вы не найдете его с помощью этого метода.
ErikE

17

[Поздний ответ, но, надеюсь, полезно]

Использование системных таблиц не всегда дает 100% правильные результаты, поскольку может существовать вероятность того, что некоторые хранимые процедуры и / или представления будут зашифрованы, и в этом случае вам потребуется использовать соединение DAC для получения необходимых данных.

Я бы порекомендовал использовать сторонний инструмент, такой как ApexSQL Search, который может легко работать с зашифрованными объектами.

Системная таблица Syscomments выдаст нулевое значение для текстового столбца, если объект зашифрован.


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
Это не включает триггеры, такие как заданный вопрос
Enkode

Действительно для представлений, хранимых процедур, пользовательских таблиц ? а для триггеров, функций, ограничений, правил, значений по умолчанию ?
Kiquenet

5

Это будет работать для вас:

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

Недействительно для ограничений ( type = 'C')?
Kiquenet

4

Существуют гораздо лучшие решения, чем изменение текста хранимых процедур, функций и представлений при каждом изменении связанного сервера. Вот несколько вариантов:

  1. Обновите связанный сервер. Вместо использования связанного сервера с именем , его IP - адрес, создать связанный сервер с именем ресурса , таких как Financeили DataLinkProdили некоторые такие. Затем, когда вам нужно изменить, какой сервер достигнут, обновите связанный сервер, чтобы он указывал на новый сервер (или удалите его и создайте заново).

  2. К сожалению, вы не можете создавать синонимы для связанных серверов или схем, но МОЖЕТЕ делать синонимы для объектов, которые расположены на связанных серверах. Например, ваша процедура [10.10.100.50].dbo.SPROCEDURE_EXAMPLEможет быть псевдонимом. Возможно создать схему datalinkprod, затем CREATE SYNONYM datalinkprod.dbo_SPROCEDURE_EXAMPLE FOR [10.10.100.50].dbo.SPROCEDURE_EXAMPLE;. Затем напишите хранимую процедуру, которая принимает имя связанного сервера, который запрашивает все потенциальные объекты из удаленной базы данных и (повторно) создает для них синонимы. Все ваши SP и функции переписываются только один раз, чтобы использовать имена синонимов, начинающиеся с datalinkprodи после этого, чтобы переключаться с одного связанного сервера на другой, который вы только что делаете, EXEC dbo.SwitchLinkedServer '[10.10.100.51]';и через доли секунды вы используете другой связанный сервер.

Там может быть даже больше вариантов. Я настоятельно рекомендую использовать превосходные методы предварительной обработки, настройки или косвенного обращения, а не изменять написанные человеком сценарии. Автоматическое обновление машинных скриптов - это хорошо, это предварительная обработка. Делать вещи вручную ужасно.


Я согласен с вашим предложением. Но в ситуации, подобной описанной в OP, вам все равно нужно найти все хранимые процедуры, содержащие IP-адрес сервера. И даже если вам нужно сделать это только один раз, ручная работа может быть большой работой.
Пол Грок

@PaulGroke Да, эта «большая» работа - это технический долг, вызванный плохим техническим выбором в укоренившейся системе. Требуется время, чтобы оправиться от этого - погасить накопленный долг. Но я предлагаю как создать техническое богатство - тратить больше времени сейчас, чтобы быть быстрее, гибче и надежнее в дальнейшем. Прочитайте статью Большой шарик грязи для некоторых идей об этом.
ErikE

Я имел в виду следующее: что плохого в том, чтобы уменьшить эту работу по «погашению долга» с помощью одного из утверждений SELECT, которые другие разместили здесь?
Пол Грок

@PaulGroke Нет ничего плохого в быстром способе поиска объектов, которые могут ссылаться на связанный сервер. Но вы знаете старую поговорку о «научить человека ловить рыбу», а не «дать человеку рыбу»? Да. Эта вещь
ErikE

@ErikE Дело в том, что вы не учите его ловить рыбу, просто говорите, что если он ловит рыбу, он может добывать пищу. Ваш ответ - отличный совет, но он не помогает ОП на самом деле его реализовать. Добавление способа найти эти ссылки, чтобы вы могли заменить их на что-то более качественное, улучшило бы этот ответ.
Т. Сар


2

Этот я пробовал в SQL2008, который может искать от всех БД за один раз.

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

Я использую это для работы. оставьте [] в поле @TEXT, похоже, хотите вернуть все ...

ВКЛЮЧИТЬ СЧЕТ

ОБЪЯВИТЬ @TEXT VARCHAR (250)
ОБЪЯВИТЬ @SQL VARCHAR (250)

SELECT @ TEXT = '10 .10.100.50 '

CREATE TABLE #results (дБ VARCHAR (64), имя объекта VARCHAR (100), xtype VARCHAR (10), определение TEXT)

ВЫБЕРИТЕ @TEXT как «Строка поиска»
ОБЪЯВИТЬ #databases CURSOR FOR SELECT NAME FRAM master..sysdatabases, где dbid> 4
    ОБЪЯВИТЬ @c_dbname varchar (64)   
    OPEN #database
    FETCH #database INTO @c_dbname   
    WHILE @@ FETCH_STATUS -1
    НАЧАТЬ
        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 [определение] LIKE' '%' + @ TEXT + '%' ''   
        EXEC (@SQL)
        FETCH #database INTO @c_dbname
    КОНЕЦ
    ЗАКРЫТЬ # базы данных
DEALLOCATE # базы данных

SELECT * FROM #results в порядке дБ, xtype, имя объекта
DROP TABLE #results

0

Я использовал это в прошлом:

В этом конкретном случае, когда вам нужно заменить определенную строку в хранимых процедурах, первая ссылка, вероятно, более актуальна.

Немного не по теме, надстройка Quick Find также полезна для поиска имен объектов в SQL Server Management Studio. Есть модифицированная версия, доступная с некоторыми улучшениями, и другая более новая версия, также доступная в Codeplex, с некоторыми другими полезными надстройками.


0

Любой поиск с оператором select дает вам только имя объекта, в котором содержится ключевое слово для поиска. Самый простой и эффективный способ - получить скрипт процедуры / функции, а затем выполнить поиск в сгенерированном текстовом файле, я также следую этой методике :) Так что вы точно знаете.


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

0

Только что написал это для общего полного внешнего перекрестного ссылки

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

Вы можете искать в определениях всех объектов базы данных, используя следующий 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%'
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.