Подтвердить что ты не робот

Как я могу сделать что-то вроде: USE @databaseName

 DECLARE @DatabaseName NVARCHAR(max); SET @DatabaseName = 'MainDb'
 USE @DatabaseName

Не получилось. Как это сделать?

4b9b3361

Ответ 1

Вам нужно будет использовать динамический SQL, если вы хотите сделать это динамически. Было бы означать все, что вы хотите выполнить в контексте этой БД, вам также нужно включить в динамический оператор SQL.

то есть. предположим, что вы хотите перечислить все таблицы в MainDB:

Это не сработает, так как оператор USE находится в другом контексте - после запуска EXECUTE следующий SELECT НЕ будет запущен в том же контексте и поэтому не будет работать в MainDb (если только соединение не было уже установлен в MainDb)

DECLARE @DatabaseName NVARCHAR(MAX)
SET @DatabaseName = 'MainDb'
EXECUTE('USE ' + @DatabaseName) -- SQL injection risk!
SELECT name FROM sys.tables

Итак, вам нужно будет сделать:

DECLARE @DatabaseName NVARCHAR(MAX)
SET @DatabaseName = 'MainDb'
EXECUTE('USE ' + @DatabaseName + ';SELECT name FROM sys.tables') -- SQL injection risk!

Конечно, вам нужно быть очень осторожным с SQL-инъекцией, для чего я указываю вам ссылку на ответ Барри.

Чтобы предотвратить SQL Injection, вы также можете использовать QUOTENAME(), она обертывает параметр в квадратных скобках:

DECLARE @DatabaseName sysname = 'MainDb'
    , @SQL NVARCHAR(MAX);

SET @SQL = N'USE ' + QUOTENAME(@DatabaseName);

PRINT(@SQL);
-- USE [MainDb]

EXECUTE(@SQL);

Ответ 2

Если вы используете script в SSMS, вы можете использовать режим SQLCMD (найденный в меню Query) до script переменная для имени вашей базы данных.

:setvar database "MainDb"
use $(database)
go

select * from sys.tables

Ответ 3

Использовать синонимы вместо

Вместо динамического SQL, чтобы сделать эквивалент USE @Database, могу ли я представить, что некоторый "предварительно обработанный динамический SQL" может быть еще лучшим решением для вас? Конечно, это зависит от того, зачем вам нужен динамический оператор USE. Я предполагаю, что вы действительно не можете с самого начала использовать правильную базу данных из своей строки подключения (что на самом деле является лучшим способом справиться с этим).

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

CREATE SYNONYM dbo.CustomName FOR SomeDatabase.SomeSchema.SomeObject

Затем в хранимой процедуре или независимо от того, что вы хотели сделать после своего динамического оператора USE, просто обратитесь к dbo.CustomName.

Чтобы легко переключаться, вы могли бы создать небольшую инфраструктуру. Создайте таблицу с псевдонимами синонимов и каким объектом они будут отображаться. Создайте хранимую процедуру, которая читает эту таблицу и запускает динамический SQL для обновления ваших SYNONYM.

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

Caveat

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

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

Ответ 4

EXEC('USE ' + @DatabaseName + ';SELECT --etc')

Пока вы доверяете @DatabaseName, чтобы не содержать ;DROP DATABASE MyDB:)

Ответ 5

Для достижения этой цели вам придется использовать Dynamic SQL.

Прежде чем приступать к изучению динамического SQL, я предлагаю вам прочитать эту замечательную статью http://www.sommarskog.se/dynamic_sql.html

Ответ 6

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

 EXECUTE('USE ' + @DatabaseName + ';select * from INFORMATION_SCHEMA.TABLES;
          select * from INFORMATION_SCHEMA.COLUMNS;
          select * from INFORMATION_SCHEMA.ROUTINES;
          select * from INFORMATION_SCHEMA.PARAMETERS;')

вы можете пойти в Old School, используя утилиту SQLCMD и используя вашу любимую программу сценариев. Я бы порекомендовал PowerShell, но для этого образца я буду использовать классические партии DOS.

Предположим, что у вас есть файл C:\input.sql, который выглядит так:

select * from INFORMATION_SCHEMA.TABLES;
select * from INFORMATION_SCHEMA.COLUMNS;
select * from INFORMATION_SCHEMA.ROUTINES;
select * from INFORMATION_SCHEMA.PARAMETERS;

Вы можете выполнить этот input.sql для нескольких dbs, поставив следующий пакетный файл C:\Test.bat(этот пакет предполагается в том же каталоге, что и input.sql)

C:\Test.bat

set var=maindb

"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -d %var% -i"input.sql"

set var=master

"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -d %var% -i"input.sql"

Затем вы можете выполнить его

C: \ > Test.bat

Преимущества этого подхода:

  • вы можете разработать свой Input.SQL, поскольку вы обычно будет
  • Он также не имеет ограничений Varchar, которые EXECUTE имеет.
  • Множество опций со сценариями PowerShell, VBS, MS DOS Batch, Shell Execute
  • Множество параметров SQLCMd (выходной файл, тайм-ауты и т.д.)

Ответ 7

Я нашел сочетание SYNONYM и exec dynamic SQL, единственное, что я получил, чтобы работать (esp как часть хранимой процедуры с несколькими базами данных). Упрощенная версия того, что сработало для меня, чтобы запросить базу данных из имени переменной.

CREATE PROCEDURE DM_TCM_TO_COMCARE 
    @FROM_DB varchar(100) = '',
    @TO_DB varchar(100) = ''
AS
BEGIN
    --CHECK INPUT VARIABLES

    DROP SYNONYM dbo.From_TableA 
    SET @SQL_SCRIPT = 'CREATE SYNONYM dbo.From_TableA FOR ['[email protected]_DB+'].[dbo].[TableA]'
    exec (@SQL_SCRIPT)

    DROP SYNONYM dbo.To_TableB
    SET @SQL_SCRIPT = 'CREATE SYNONYM dbo.To_TableB FOR ['[email protected]_DB+'].[dbo].[TableB]'
    exec (@SQL_SCRIPT)

    select * from dbo.From_TableA
    select * from dbo.To_TableB

    insert into dbo.To_TableB 
         select * from dbo.From_TableA where 1 = 1
    -- etc
END
GO