У меня есть приведенный ниже скрипт, который отлично работает и дает все нужные мне результаты. Однако он делает это только для текущего контекста БД. У меня несколько сотен баз данных в моем экземпляре, и мне нужно получить результаты для всех баз данных за одно выполнение. Как изменить скрипт, чтобы он работал для всех баз данных.
IF OBJECT_ID('tempdb..#AllInfo', N'U') IS NOT NULL DROP TABLE #AllInfo;
CREATE TABLE #AllInfo (
dbase_name nvarchar(200),
tbl_name nvarchar(300),
column_name nvarchar(300),
min_date datetime
)
DECLARE @Statement varchar(2000);
DECLARE cr_MaxDateTime CURSOR LOCAL FOR
SELECT 'SELECT DB_NAME(), ' + '''' + TAB.name + '''' + ', ' + '''' + COL.name + '''' +' ,MIN([' + COL.name +']) AS ''Min' + COL.name + '_' + TAB.name + ''' FROM [' + SCH.name + '].[' + TAB.name + ']'
FROM sys.schemas AS SCH
INNER JOIN sys.tables AS TAB
ON TAB.schema_id = SCH.schema_id
INNER JOIN sys.columns AS COL
ON COL.object_id = TAB.object_id
INNER JOIN sys.types AS UDT
ON COL.user_type_id = UDT.user_type_id
INNER JOIN sys.types AS TYP
ON TYP.system_type_id = UDT.system_type_id AND
TYP.user_type_id = TYP.system_type_id AND
TYP.name IN ('date', 'datetime2', 'datetimeoffset', 'datetime', 'time')
ORDER BY SCH.name, TAB.name, COL.name
FOR READ ONLY;
OPEN cr_MaxDateTime;
FETCH cr_MaxDateTime INTO @Statement;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @Statement;
INSERT INTO #AllInfo
EXECUTE(@Statement);
FETCH cr_MaxDateTime INTO @Statement;
END;
CLOSE cr_MaxDateTime;
DEALLOCATE cr_MaxDateTime;
select * from #AllInfo
Я знаю, что sp_MSForEachDB может помочь, но примеры, которые мне удалось найти, — это в основном однострочные команды. Я не мог заставить его работать для всего сценария.
Отвечает ли это на ваш вопрос? Выполнение SQL-запроса к нескольким базам данных
Re: sp_msforeachdb, Это ничем не отличается от длинного скрипта, просто создайте большую длинную строку со всем этим и прикрепите ?. к каждой таблице, чтобы он поправил базу данных или добавил ЕГЭ?. Однако это довольно хлопотно, так как вам обычно приходится заменять множество кавычек и т. д., Чтобы заставить его работать.
Я пробовал sp_msforeachdb. Как видите, в существующем скрипте уже довольно много цитат. Я просто не мог заставить это работать после замены всех кавычек. Это просто дает мне ту или иную ошибку.
Предполагая, что вы используете современную и поддерживаемую версию SQL Server, более простой способ удалить таблицу #temp (конечно, ненужную, если вы поместите этот код в хранимую процедуру):
DROP TABLE IF EXISTS #AllInfo;
CREATE TABLE #AllInfo
(
dbase_name nvarchar(130),
tbl_name nvarchar(260),
column_name nvarchar(130),
min_date datetime
);
Вот один из способов, которым вы можете взять базовый оператор SQL и условно выполнить этот динамический SQL в каждой базе данных. Я изо всех сил старался избегать одинарных кавычек, но иногда это делает текст менее читаемым.
DECLARE @base nvarchar(max) = N'SELECT DB_NAME(),
CONCAT($schn$, char(46), $tbn$),
$coln$, MIN($col$) FROM $sch$.$tb$;',
@nested nvarchar(max) = N'DECLARE @sql nvarchar(max) = SPACE(0);
SELECT @sql += REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@base,
N''$sch$'', QUOTENAME(s.name)), N''$schn$'', QUOTENAME(s.name, char(39))),
N''$tb$'', QUOTENAME(t.name)), N''$tbn$'', QUOTENAME(t.name, char(39))),
N''$col$'', QUOTENAME(c.name)), N''$coln$'', QUOTENAME(c.name, char(39)))
FROM sys.schemas AS s
INNER JOIN sys.tables AS t ON s.[schema_id] = t.[schema_id]
INNER JOIN sys.columns AS c ON t.[object_id] = c.[object_id]
WHERE EXISTS (
SELECT 1 FROM sys.types
WHERE system_type_id IN (40,41,42,43,61)
AND user_type_id = c.user_type_id);
INSERT #AllInfo EXEC sys.sp_executesql @sql;';
DECLARE @context nvarchar(2000), @c cursor;
SET @c = CURSOR FORWARD_ONLY STATIC READ_ONLY FOR
SELECT QUOTENAME(name) + N'.sys.sp_executesql'
FROM sys.databases WHERE state = 0 AND database_id > 4;
OPEN @c; FETCH NEXT FROM @c INTO @context;
WHILE @@FETCH_STATUS <> -1
BEGIN
EXEC @context @nested, N'@base nvarchar(max)', @base;
FETCH NEXT FROM @c INTO @context;
END
По сути, нам нужно подготовить оператор, который можно запустить в каждой базе данных, а затем внутри каждой базы данных для каждого столбца, соответствующего нашим критериям. Таким образом, у нас есть вложенный динамический SQL, который настраивается внутри курсора базы данных, заменяя токены, такие как $sch$, на фактическое имя схемы, $tb$ на фактическое имя таблицы и $col$ на фактическое имя столбца. REPLACE() запутан, и я изначально пошел по этому пути, потому что я ссылался на каждый токен более одного раза, но это усложнилось, потому что в некоторых местах его нужно было отображать как строковый литерал, а не как имя объекта в квадратных скобках.
Окончательно:
SELECT * FROM #AllInfo;
Кроме того, пожалуйста, держитесь подальше от sp_MSforeachdb. Эта процедура недокументирована и не поддерживается по одной причине: она содержит ошибки и пропускает базы данных без предупреждения. Это также заставляет вас ссылаться на базу данных с помощью ?, что может быть утомительным и даже проблематичным. Я написал замену здесь, что позволяет избежать ошибки, а также не дает вам захламлять ваши динамические SQL-команды ?. Подробнее об этом можно прочитать в следующих постах (даже не все мои):
Здравствуйте @Aaron Bertrand, большое спасибо, и я очень ценю время, которое вы потратили на написание кода и его подробное объяснение вместе со ссылками. Я все еще пытаюсь осмыслить это и лучше понять [частично из-за собственной неопытности :)]. Тем временем я выполнил код в своей среде, и он каким-то образом ограничивает извлекаемые результаты, например, когда я выполняю исходный скрипт для 1 базы данных, он дает мне более 100 столбцов с min_date. Однако ваш вышеприведенный скрипт извлекает только 43 записи для всех баз данных вместе. Есть ли там фильтр, ограничивающий результаты?
@VineethNair Я заметил проблему, попробуйте обновленный запрос.
После сравнения результатов кажется, что скрипт выдает 1 строку вывода для каждой базы данных. Итак, изначально, если моя база данных имеет более 100 столбцов (в нескольких таблицах), которые соответствуют критериям, вместо того, чтобы выводить 100 x количество БД (в данном случае 43). Это просто дает мне 43 строки вывода. Столбцы также, кажется, выбираются случайным образом для каждой БД.
Извините, я пропустил ваше редактирование запроса. Теперь он работает нормально. Еще раз спасибо :)
Отвечает ли это на ваш вопрос? SQL Server: запустить скрипт на всех базах данных