Как запустить хранимую процедуру в нескольких базах данных - PullRequest
1 голос
/ 30 июля 2009

В одном экземпляре SQL Server у меня есть следующие базы данных:

  • Штаб-квартира
  • Branch001
  • Branch002
  • Branch003

...

  • Отделение NNN

В каждой БД филиала есть процедура под названием usp_ComputeDailySales, которая выполняет некоторые вычисления и записывает ежедневные данные о продажах в БД Headquarters. Как написать одну хранимую процедуру в БД штаб-квартиры для выполнения usp_ComputeDailySales во всех БД филиала?

Я мог бы написать что-то вроде кода ниже, но я думаю, что это не тот путь.

USE Branch001
EXEC usp_ComputeDailySales

USE Branch002
EXEC usp_ComputeDailySales

...

Я хотел каким-то образом выполнить процедуру для всех БД филиала одновременно.

Ответы [ 4 ]

2 голосов
/ 30 июля 2009

Это не динамический SQL, а основывается на чем-то вроде отложенного разрешения имен.

ВЫПОЛНИТЬ , см. @module_name_var параметр

DECLARE @sql varchar(300)
SELECT
    [name] + '..usp_ComputeDailySales' AS Cmd
INTO #List
FROM
    sys.databases d WHERE d.[name] LIKE 'branch%'
    OR --Thanks Mitch
    d.[name] = 'Headquarters'

WHILE EXISTS (SELECT * FROM #List)
BEGIN
    SELECT TOP 1 @SQL = Cmd FROM #List
    EXEC @SQL
    DELETE #List WHERE Cmd = @SQL
END

Редактировать, после комментария КМ

Да, есть разница, но я уточню:

EXEC (@SQL) означает, что @SQL может быть 'SELECT * FROM foo' ИЛИ ​​'DELETE User WHERE 1=1';.)

EXEC @SQL означает, что @SQL - это имя объекта. Так что я должен был использовать @ Obj

Итак, вы можете сделать это:

DECLARE @Obj varchar(200)
SELECT @Obj = 'dbo.uspCustomHook'
IF OBJECT_ID(@Obj) IS NOT NULL
    EXEC @Obj @p1 = 1, @p2 = 'bob', ...

Это позволяет избежать отложенных ошибок разрешения имен. Когда пакет / процесс скомпилирован, ошибки не возникает, если dbo.uspCustomHook не существует.

Я не использовал эту технику начиная с SQL 2000, и я не знаю, достаточно ли умна SQL 2005 (перекомпиляция на уровне операторов), чтобы выяснить, нужно ли запускать @Obj, потому что он не существует, поэтому его нет попробуй скомпилировать оператор EXEC ...

Это также полезно для кросс-баз данных, запросов одинаковых экземпляров. Вы можете настроить prd-prod, dev-dev и т. Д., Не полагаясь на связанные серверы или жестко закодированные имена баз данных.

0 голосов
/ 30 июля 2009

Вы можете сделать это довольно легко с помощью sp_msForEachDB. В первом примере здесь будет запущен процесс для каждой базы данных с именем LIKE 'Branch%':

EXECUTE sp_msForEachDB '
IF ''?'' like  ''Branch%''
 BEGIN
    USE ?
    EXECUTE usp_ComputeDailySales
 END
'

И этот будет запускать его в каждой базе данных (независимо от имени), содержащей хранимую процедуру с таким именем:

EXECUTE sp_msForEachDB '
USE ?
IF object_id(''usp_ComputeDailySales'') is not null
    EXECUTE usp_ComputeDailySales
'

Возни и возни с этим - они работают, но им нужно немного привыкнуть.

Дополнения: хотя это «недокументированная функция», она существует с SQL Server 7.0 и, возможно, ранее. Есть любое количество статей и примеров, использующих его, и, возможно, любое количество систем Enterprise, основанных на нем, некоторые из которых я создал. У меня действительно никогда не было проблем с этим (как только я получил? И двойные верны, то есть.)

0 голосов
/ 30 июля 2009

Просто обратитесь к ним с их полностью определенными именами, такими как:

<Database Name>.<owner>.<table>

и замените значения.

Пример: CustomerDatabase.dbo.Users

А в вашем случае это будет выглядеть так:

exec Branch001.dbo.usp_ComputeDailySales
exec Branch002.dbo.usp_ComputeDailySales
exec Branch003.dbo.usp_ComputeDailySales

Предполагается, что один пользователь имеет разрешения для всех этих баз данных.

0 голосов
/ 30 июля 2009

вы можете использовать недокументированную хранимую процедуру с именем sp_MSforeachdb

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...