Использование @databases:
Как уже упоминалось в комментариях к вашему вопросу, переменные не могут использоваться для динамического выбора базы данных. Динамический sql указывается. Вы можете начать с создания вашего шаблона SQL-оператора:
declare @sql nvarchar(max) =
'union all ' +
'select ''@db'' as db, name, email ' +
'from [@db].dbo.users ';
Поскольку у вас есть SQL Server 2016, вы можете разделить, используя функцию string_split
, с вашей переменной @databases
в качестве входных данных. Это приведет к появлению таблицы со значением в качестве имени столбца, в которой хранятся имена базы данных.
Используйте функцию replace
для замены @db
в шаблоне на value
. Это приведет к одному выражению sql для каждой базы данных, которую вы передали в @databases. Затем объедините утверждения обратно вместе. К сожалению, в версии 2016 нет встроенной функции для этого. Таким образом, мы должны использовать знаменитый трюк for xml
, чтобы соединить операторы, затем мы используем .value
, чтобы преобразовать его в строку, и, наконец, мы используем stuff
, чтобы избавиться от ведущего оператора union all
.
Возьмите результаты каскадного вывода и перезапишите переменную @sql
. На этом этапе все готово, поэтому выполните его.
Я делаю все, что описано в этом коде:
declare @databases nvarchar(max) = 'db_1,db_2';
set @sql = stuff(
(
select replace(@sql, '@db', value)
from string_split(@databases, ',')
for xml path(''), type
).value('.[1]', 'nvarchar(max)')
, 1, 9, '');
exec(@sql);
Без проверки, конечно, но если вы печатаете вместо выполненияПохоже, что это дает правильный SQL-оператор для ваших нужд.
Использование msForEachDB:
Теперь, если вы не хотите знать, какие базы данных имеют «пользователей», например, есливы находитесь в среде, где у вас есть разные базы данных для каждого клиента, вы можете использовать sp_msForEachDb и сначала проверить структуру, чтобы убедиться, что в ней есть таблица 'users' со столбцами 'name' и 'email'. Если это так, выполните соответствующий оператор. Если нет, выполнить фиктивный оператор. Я не буду описывать это, я просто дам код:
declare @aggregator table (
db sysname,
name int,
email nvarchar(255)
);
insert @aggregator
exec sp_msforeachdb '
declare @sql nvarchar(max) = ''select db = '''''''', name = '''''''', email = '''''''' where 1 = 2'';
select @sql = ''select db = ''''?'''', name, email from ['' + table_catalog + ''].dbo.users''
from [?].information_schema.columns
where table_schema = ''dbo''
and table_name = ''users''
and column_name in (''name'', ''email'')
group by table_catalog
having count(*) = 2
exec (@sql);
';
select *
from @aggregator