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

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

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

    
задан Agzam 24.09.2010 в 17:30
источник

7 ответов

19

Вам нужно будет использовать динамический 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);
    
ответ дан AdaTheDev 24.09.2010 в 17:39
источник
12

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

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

select * from sys.tables
    
ответ дан Joe Stefanelli 24.09.2010 в 18:13
источник
5

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

Вместо динамического 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.

    
ответ дан ErikE 25.09.2010 в 01:10
источник
2
EXEC('USE ' + @DatabaseName + ';SELECT --etc')

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

    
ответ дан Chris Diver 24.09.2010 в 17:32
источник
1

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

Прежде чем вы начнете изучать динамический SQL, я предлагаю вам прочитать эту замечательную статью Ссылка

    
ответ дан codingbadger 24.09.2010 в 17:34
источник
1

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

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

вы можете пойти в Старую школу, используя 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 Server0\Tools\Binn\SQLCMD.EXE" -d %var% -i"input.sql"

set var=master

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

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

C: \ & GT; Test.bat

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

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

Я нашел сочетание 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 ['+@FROM_DB+'].[dbo].[TableA]'
    exec (@SQL_SCRIPT)

    DROP SYNONYM dbo.To_TableB
    SET @SQL_SCRIPT = 'CREATE SYNONYM dbo.To_TableB FOR ['+@TO_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
    
ответ дан John 20.09.2016 в 08:46
источник