Як знайти текст у процедурах / тригерах 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)
Chris Rodriguez

2
@ChrisRodriguez, хороша ідея, але пам’ятайте, що це буде лише перша відповідність можливо багатьох у межах кожної процедури / тригера / функції
KM.

Недійсні для обмежень ( type = 'C')?
Кікенет

18

Ви можете знайти його як

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

У ньому буде перераховано чіткі збережені імена процедур, які містять текст на зразок "Користувач" всередині збереженої процедури. Більше інформації


8
Просто пам’ятайте, що syscommentsтаблиця зберігає значення в шматки 8000 символів, тому, якщо вам не пощастить, щоб текст, який ви шукаєте, розбитий через одну з цих меж, ви не знайдете його за допомогою цього методу.
ЕрікЕ

17

[Пізня відповідь, але, сподіваюся, корисна]

Використання системних таблиць не завжди дає стовідсоткові правильні результати, оскільки може бути ймовірність, що деякі збережені процедури та / або представлення зашифровані, і в цьому випадку для отримання потрібних даних вам потрібно буде використовувати з'єднання ЦАП .

Я рекомендую використовувати сторонній інструмент, такий як ApexSQL Search, який може легко працювати з зашифрованими об'єктами.

Системна таблиця системних коментарів дасть нульове значення для текстового стовпця у випадку, якщо об’єкт зашифрований.


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
Це не включає
триггери,

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

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')?
Кікенет

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]';і за частку секунди ви використовуєте інший пов'язаний сервер.

Можливо, буде ще більше варіантів. Я настійно рекомендую використовувати передові методики попередньої обробки, конфігурації чи опосередкування, а не зміни сценаріїв, написаних людиною. Автоматичне оновлення створених машинами скриптів добре, це попередня обробка. Робити речі вручну - жахливо.


Я згоден з вашою пропозицією. Але в такій ситуації, як описана в ОП, вам все-таки потрібно знайти всі збережені процедури, що містять IP-адресу сервера. І навіть якщо вам доведеться це зробити лише один раз, зробити це вручну може бути багато роботи.
Пол Грок

@PaulGroke Так, ця "велика" робота - це технічна заборгованість, викликана поганим технічним вибором у закріпленій системі. Щоб відновитись із цього потрібно - погасити нараховану заборгованість. Але моя пропозиція полягає в тому, як створити технічне багатство - витрачати більше часу, щоб пізніше бути швидшим, спритнішим і надійнішим. Прочитайте статтю « Велика кулька грязі», щоб отримати деякі ідеї навколо цього.
ErikE

Що я мав на увазі: що не так, зменшуючи роботу "виплати боргу", використовуючи одну з SELECT заяв, які тут розміщували інші?
Пол Грок

@PaulGroke Швидкий спосіб пошуку об’єктів, які можуть посилатися на пов'язаний сервер, не має нічого поганого. Але ви знаєте, що стара приказка про "навчити людину ловити рибу", а не "дати людині рибу"? Так. Та річ.
ЕрікЕ

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


2

Цей я спробував у SQL2008, який за один раз може шукати з усіх db.

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 '

СТВОРИТИ ТАБЛИЦУ # результати (db VARCHAR (64), ім'я об'єкта VARCHAR (100), xtype VARCHAR (10), визначення TEXT)

SELECT @TEXT як "Рядок пошуку"
ДЕКЛАРАЦІЯ #databases CURSOR ДЛЯ ВИБІРУТЬСЬОГО ІМЯ З master..sysdatabases, де dbid> 4
    DECLARE @c_dbname varchar (64)   
    ВІДКРИТИ #дані
    ВЗАЄМО #databases INTO @c_dbname   
    WHILE @@ FETCH_STATUS -1
    ПОЧАТОК
        SELECT @SQL = 'ВСТАВЛЯЙТЕ В #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)
        ВЗАЄМО #databases INTO @c_dbname
    Кінець
    ЗАКРИТИ #дані
РОЗКРИТИ #дані

ВИБІР * ВІД # впорядкувати порядок за db, xtype, ім'ям об'єкта
СКЛАД ТАБЛИЦІ #результати

0

Я раніше їх використовував:

У цьому конкретному випадку, коли вам потрібно замінити певний рядок через збережені процедури, перше посилання, ймовірно, є більш релевантним.

Трохи поза темою, надбудова « Швидкий пошук» також корисна для пошуку імен об’єктів за допомогою 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.