Как динамически изменить базу данных с помощью TSQL

11

У меня проблемы с попыткой динамически изменить контекст SSMS на базу данных, указанную в динамическом SQL:

EXEC sys.sp_executesql N'USE db1 ' ;

Он выполняется успешно, однако контекст базы данных SSMS не изменяется.

Я попытался небольшое изменение выше, как

DECLARE @sql NVARCHAR(100) DECLARE @db NVARCHAR(50)
SET @db = N'db1' SET @sql = N'Use ' + @db
EXEC sp_executesql @sql

Опять же, он выполняется успешно, но база данных не меняется.

Mazhar
источник
4
Вы не можете изменить контекст в sp_executesql для сеанса, который вы используете в SSMS. Контекст действителен только во время динамического сеанса SQL, но не для сеанса SSMS.
Лотар

Ответы:

7

SSMS НЕ БУДЕТ, ПОВТОРЯЮ, НЕ ПОЛУЧИТСЯ В КОНТЕКСТЕ КОМАНДЫ ИСПОЛЬЗОВАНИЯ, КОТОРЫЙ ВЫ БУДЕТЕ ДИНАМИЧНЫМ SQL

Если конечной целью является выполнение некоторого другого динамического SQL внутри выбранной базы данных, это достаточно просто:

DECLARE @db sysname = N'db1';

DECLARE @exec nvarchar(max) = QUOTENAME(@db) + N'.sys.sp_executesql',
        @sql  nvarchar(max) = N'SELECT DB_NAME();';

EXEC @exec @sql;

Если вам нужно передать параметры, нет проблем:

DECLARE @db sysname = N'db1', @i int = 1;

DECLARE @exec nvarchar(max) = QUOTENAME(@db) + N'.sys.sp_executesql',
        @sql  nvarchar(max) = N'SELECT DB_NAME(), @i;';

EXEC @exec @sql, N'@i int', @i;

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

DECLARE @db sysname = N'db1';

DECLARE @exec nvarchar(max) = QUOTENAME(@db) + N'.sys.sp_executesql',
        @sql  nvarchar(max) = N'EXEC dbo.procedurename;';

EXEC @exec @sql;

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

Аарон Бертран
источник
Это здорово, спасибо Аарону Бертрану. И нет, конечная цель состоит в том, чтобы не запустить весь этот код в SSMS просто так , что SSMS теперь в контексте @db
Mazhar
2

На самом деле dynamicSQL не выполняется конкретно в строке с остальной частью вашего кода, это отдельная сущность (даже если он запускается, как если бы он был в строке

Если вы запустите код: SET @sql = N'Use ' + @db + '; select DB_NAME(); select @@spid'на месте вашего текущего набора вы заметите, что возвращающиеся результаты указывают, что вы переместили активную базу данных, но все еще работаете в том же соединении.

Если вы хотите изменить выбор базы данных, лучше всего сделать что-то вроде этого:

IF @db = 'db1'
    USE db1
ELSE IF @db = 'db2'
    USE db2

Он не очень приятный или чистый и требует двух строк для каждой потенциальной базы данных, но он выполнит свою работу (не запускайте его в динамическом SQL, иначе у вас все равно останется та же проблема, что и основной поток не изменился)

Обратите внимание, что использование команд USE запрещено в процедурах / функциях

Ste Bov
источник