Умный способ использования SQLCMD с динамическим вызовом
У меня есть этот код SQLCMD MSSQL, который может входить в базу данных и в этом случае делать инструкцию SELECT:
:CONNECT czasql-001
SELECT * FROM [Lps_Hepper_Cz].[config].[LpsPlant]
GO
:CONNECT LS_Hepper_DK
SELECT * FROM [LPS_Hepper_NY].[config].[LpsPlant]
:CONNECT LS_Hepper_DK
SELECT * FROM [LPS_Hepper_DK].[config].[LpsPlant]
:CONNECT LS_Hepper_DK
SELECT * FROM [LPS_Hepper_SUPPLIER].[config].[LpsPlant]
GO
:CONNECT LS_Hepper_372
SELECT * FROM [LPS_Hepper_MO].[config].[LpsPlant]
GO
:CONNECT LS_Hepper_678
SELECT * FROM [LPS_Hepper_678].[config].[LpsPlant]
GO
Это решение работает нормально, но требует, чтобы я скопировал копию несколько раз, чтобы изменить имя базы данных. Но может ли кто-то помочь мне улучшить это, используя вместо этого цикл. Я попытался использовать временную таблицу. Например:
declare @tbl table (ServerName nvarchar(50), DbName nvarchar(50), IsDone bit default(0))
insert into @tbl (ServerName,DbName) VALUES ('CZASQL-001', '[Lps_Hepper_CZ]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_DK]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_NY]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_Supplier]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_372', '[Lps_Hepper_MO]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_678', '[Lps_Hepper_678]')
Но я не могу понять, как сделать логику для итерации через базу данных, подключиться к серверу и установить имя базы данных, когда данные у меня есть как nvarchar?
У кого-нибудь есть предложение?
UPDATE:
Я буду использовать это только для INSERT/UPDATE или DELETE. Поэтому я не использую хранимую процедуру. Мне нравится использовать это для обновления данных обо всех наших базах данных. Поэтому я буду использовать только таблицу temp, которая должна быть частью script.
Имена серверов и имена баз данных будут получены из таблицы temp выше. Название таблицы одинаково для всех баз данных, потому что у нас есть копии базы данных по всему миру для ограничения загрузки данных. Мне нужно убедиться, что когда я обновляю один, я также обновляю остальные.
Обновление 2:
Я попытался поиграть с ним, но я продолжаю останавливаться, не имея возможности использовать значения в таблице temp. Это означает, что я не могу использовать: SETVAR для установки имени сервера:
declare @tbl table (ServerName nvarchar(50), DbName nvarchar(50), IsDone bit default(0))
insert into @tbl (ServerName,DbName) VALUES ('CZASQL-001', '[Lps_Hepper_CZ]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_DK]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_NY]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_Supplier]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_372', '[Lps_Hepper_MO]')
insert into @tbl (ServerName,DbName) VALUES ('LS_Hepper_678', '[Lps_Hepper_678]')
WHILE (SELECT COUNT(*) FROM @tbl WHERE IsDone = 0) > 0
BEGIN
DECLARE @selectedRow INT = (SELECT TOP 1 Id FROM @tbl WHERE IsDone = 0)
--DECLARE @ServerName NVARCHAR(50)= (SELECT ServerName FROM @tbl WHERE Id = @selectedRow)
--DECLARE @DatabaseName NVARCHAR(50) = (SELECT DbName FROM @tbl WHERE Id = @selectedRow)
DECLARE @ServerName sysname= (SELECT ServerName FROM @tbl WHERE Id = @selectedRow)
DECLARE @DatabaseName sysname = (SELECT DbName FROM @tbl WHERE Id = @selectedRow)
:SETVAR DatabaseName @DatabaseName
:SETVAR ServerName @ServerName
SELECT ServerName --This looks correctly
print CONVERT(NVARCHAR(100),@selectedRow)
:CONNECT ServerName
USE @DatabaseName
GO
SELECT * FROM [config].[LpsPlant]
GO
UPDATE @tbl SET IsDone = 1 WHERE Id = @selectedRow
END;
Ответы
Ответ 1
Я буду использовать это только для INSERT/UPDATE или DELETE. Поэтому я не использую хранимую процедуру. Мне нравится использовать это для обновления данных обо всех наших базах данных.
Если это так, вы можете использовать Registered Servers
:
Преимущества зарегистрированных серверов
С зарегистрированными серверами вы можете:
-
Зарегистрировать серверы, чтобы сохранить информацию о подключении.
-
Определите, работает ли зарегистрированный сервер.
-
Простое подключение Обозревателя объектов и Редактора запросов к зарегистрированному серверу.
-
Изменить или удалить регистрационную информацию для зарегистрированного сервера.
-
Создать группы серверов.
-
Обеспечьте удобные имена для зарегистрированных серверов, указав значение в поле имени зарегистрированного сервера, которое отличается от Список имен серверов.
-
Предоставьте подробные описания для зарегистрированных серверов.
-
Предоставьте подробное описание зарегистрированных групп серверов.
-
Экспорт зарегистрированных групп серверов.
-
Импортировать зарегистрированные группы серверов.
-
Просмотр файлов журнала SQL Server для онлайн-или автономных экземпляров SQL Server
- Выполнять одновременные действия с несколькими серверами
Вы можете создать несколько групп на основе: server/database/environment (DEV/PROD/QA).
Другая возможность - экспортировать зарегистрированные серверы в файл, поместить в систему управления версиями (SVN/ Git) и поделиться с другими разработчиками.
Используя SSMS, вы нажимаете новый запрос на основе группы серверов и выполняете один и тот же запрос сразу в нескольких базах данных.
![введите описание изображения здесь]()
Изображение из: http://sqlmag.com/site-files/sqlmag.com/files/archive/sqlmag.com/content/content/142469/Greenwood-SQL2331-Fig5-sm.jpg
Ответ 2
Выполните следующие действия:
1) Создайте сервер ссылок.
2) Запустите ниже script, я изменил ваш код snip-it
IF OBJECT_ID('tempdb..##Results') IS NOT NULL
Truncate TABLE ##Results
else
CREATE TABLE ##Results
(id int identity ,ServerName nvarchar(50), DbName nvarchar(50), IsDone bit default(0))
-- populat link server name and db name
insert into ##Results (ServerName,DbName) VALUES ('CZASQL-001', '[Lps_Hepper_CZ]')
insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_DK]')
insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_NY]')
insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_Supplier]')
insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_372', '[Lps_Hepper_MO]')
insert into ##Results (ServerName,DbName) VALUES ('LS_Hepper_678', '[Lps_Hepper_678]')
WHILE (SELECT COUNT(*) FROM ##Results WHERE IsDone = 0) > 0
BEGIN
DECLARE @selectedRow INT = (SELECT TOP 1 Id FROM ##Results WHERE IsDone = 0)
DECLARE @sq1 varchar (100) ='SELECT * FROM ' ; --
DECLARE @sql varchar (8000) = '';
DECLARE @FROM varchar (100) ='[config].[LpsPlant]' ;
select @sql = @sq1 + ServerName + '.'+ DbName+ @FROM FROM ##Results WHERE Id = @selectedRow
print @sql
exec @sql
UPDATE ##Results SET IsDone = 1 WHERE Id = @selectedRow
END;
Ответ 3
С помощью курсора это может быть:
CREATE TABLE #TEMP (ServerName nvarchar(50), DbName nvarchar(50))
insert into #TEMP (ServerName,DbName) VALUES ('CZASQL-001', '[Lps_Hepper_CZ]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_DK]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_NY]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_DK', '[Lps_Hepper_Supplier]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_372', '[Lps_Hepper_MO]')
insert into #TEMP (ServerName,DbName) VALUES ('LS_Hepper_678', '[Lps_Hepper_678]')
DECLARE @ServerName VARCHAR(100),
@DatabaseName VARCHAR(100);
DECLARE CRS CURSOR LOCAL
FOR SELECT * FROM #TEMP
FETCH NEXT FROM CRS INTO @ServerName, @DatabaseName;
WHILE @@FETCH_STATUS=0
BEGIN
print CONVERT(NVARCHAR(100),@selectedRow)
:CONNECT @ServerName
GO
USE @DatabaseName
GO
SELECT * FROM [config].[LpsPlant]
GO
FETCH NEXT FROM CRS INTO @ServerName, @DatabaseName;
END
DROP TABLE #TEMP
Ответ 4
Я не запускаю ваш код, но вижу возможную проблему при использовании слова GO
, которое не является ключевым словом SQL, но ключевое слово SQL Server/SqlCmd означает, что здесь заканчивается блок script, запускайте все в нем и ждать всех последствий ". Я не уверен, что он может работать внутри цикла WHILE
из-за этого.
Затем я вижу, что вы пытаетесь
:CONNECT ServerName
но в документации для него я вижу, что синтаксис
:CONNECT $(ServerName)
Существует также проблема вашего цикла. SQL Server не гарантирует порядок инструкции SELECT
, если вы не используете ORDER BY
. Если вам не нравится порядок выполнения инструкций, тогда это ОК, в противном случае вам нужно изменить его с помощью курсора или хотя бы добавить числовой столбец и заказать его при выборе TOP 1
.