2013-11-21 3 views
4

Я выполняю приведенную ниже хранимую процедуру sp_MSforeachdb с помощью простой команды. Мой вопрос заключается в том, чтобы ограничить результат, чтобы показать только базы данных, которые имеют по крайней мере 1 запись, удовлетворяющую команду:sp_MSforeachdb: включать только результаты из баз данных с результатами

Sample of the result

Вот моя хранимая процедура:

EXECUTE master.sys.sp_MSforeachdb 'USE [?]; 

IF (EXISTS (SELECT * 
       FROM INFORMATION_SCHEMA.TABLES 
       WHERE TABLE_NAME = ''Tabs'')) 
BEGIN 

SELECT ''?'' as dbname,T.TabName, T.TabPath 
FROM Tabs T 
WHERE T.TabID IN (

SELECT Distinct TM.TabID 
FROM TabModules TM 
WHERE mID IN (
    ... 
) 

) 
ORDER BY T.TabName 
END 
' 

Любые идеи, как я могу изменить sp, чтобы он не отображал базы данных, которые имеют пустые результаты (см. изображение)?

ответ

8

Ну, во-первых, прекратить использование sp_MSforEachDb. О, проблемы (если вы хотите доказательства, см. here, here и here).

Как насчет:

DECLARE @cmd NVARCHAR(MAX) = N'', @sql NVARCHAR(MAX) = N''; 

SELECT @cmd += N'IF EXISTS (SELECT 1 FROM ' 
    + QUOTENAME(name) + '.sys.tables WHERE name = N''Tabs'') 
    SET @sql += N''UNION ALL 
    SELECT ''''' + name + ''''',T.TabName 
    FROM ' + QUOTENAME(name) + '.dbo.Tabs AS T 
    WHERE EXISTS 
    (
     SELECT 1 FROM ' + QUOTENAME(name) + '.dbo.TabModules AS TM 
     WHERE TM.TabID = T.TabID 
     AND TM.mID IN -- this should probably be exists too 
     ( 
      ... 
     ) 
    ) 
''' 
FROM sys.databases 
    WHERE state = 0 -- assume you only want online databases 
    AND database_id > 4; -- assume you don't want system dbs 

EXEC sp_executesql @cmd, N'@sql NVARCHAR(MAX) OUTPUT', @sql OUTPUT; 

SET @sql = STUFF(@sql, 1, 10, '') + N' ORDER BY TabName;'; 

PRINT @sql; -- this will appear truncated, but trust me, it is not truncated 
-- EXEC sp_executesql @sql; 

Если вы действительно хотите, чтобы некоторые неизвестные, произвольное число отдельных ResultSets, изменение просто.

DECLARE @cmd NVARCHAR(MAX) = N'', @sql NVARCHAR(MAX) = N''; 

SELECT @cmd += N'IF EXISTS (SELECT 1 FROM ' 
    + QUOTENAME(name) + '.sys.tables WHERE name = N''Tabs'') 
    SET @sql += N''SELECT ''''' + name + ''''',T.TabName 
    FROM ' + QUOTENAME(name) + '.dbo.Tabs AS T 
    WHERE EXISTS 
    (
     SELECT 1 FROM ' + QUOTENAME(name) + '.dbo.TabModules AS TM 
     WHERE TM.TabID = T.TabID 
     AND TM.mID IN -- this should probably be exists too 
     ( 
      ... 
     ) 
    ) 
ORDER BY T.TabName; 
'';' 
FROM sys.databases 
    WHERE state = 0 -- assume you only want online databases 
    --AND database_id > 4; -- assume you don't want system dbs 

EXEC sp_executesql @cmd, N'@sql NVARCHAR(MAX) OUTPUT', @sql OUTPUT; 

PRINT @sql; -- this will appear truncated, but trust me, it is not truncated 
-- EXEC sp_executesql @sql; 
+0

Спасибо за ответ Аарон! Я попробовал ваше решение, но вместо получения фактического результата я получил SQL-запрос, который был усечен в конце (извините, я полный noob, когда речь идет о функциях и sp). И когда я выполнил этот запрос отдельно (и добавил усеченную часть), результат был все в одной таблице (по сравнению с макетом результата из sp_MSforeachdb: одна таблица результатов для каждого БД). В любом случае, чтобы изменить это представление результата? – mustang888

+0

SQL-запрос будет усечен в конце, если ваш запрос довольно большой и/или у вас есть большое количество баз данных. Я могу заверить, что на самом деле он не усекается, если у него действительно есть более миллиарда символов; это просто печальное ограничение в команде «PRINT». Я намеренно создал его как запрос UNION, потому что я не думаю, что это очень распространенное требование иметь неизвестное количество результатов. Если это то, что вы действительно хотите, вы всегда можете вывести вывод в таблицу #temp, а затем запустить курсор против этого, обрабатывая строки для каждого отдельного имени базы данных ... –

+0

hmmm, это странно, потому что он определенно пропускает последние 30 символов или поэтому из запроса, и все же запрос waaaay под миллиардом символов (только 3 базы данных удовлетворяют условиям запроса). Кроме того, как я могу заставить эту команду выполнить запрос напрямую (без выполнения вручную сгенерированного запроса)? – mustang888

1

Вам в основном нужен другой IF, чтобы запускать только выбор, если данные существуют. Вот что я сделал, чтобы проверить.

На DB1:

create table mytesttable(a int) 
insert mytesttable values(1) 

В DB2:

create table mytesttable(a int) 

Так что вы хотите DB1 возвращать результаты, но DB2 не. вы можете использовать следующий SQL:

EXECUTE master.sys.sp_MSforeachdb 'USE [?]; 

IF (EXISTS (SELECT * 
      FROM INFORMATION_SCHEMA.TABLES 
      WHERE TABLE_NAME = ''mytesttable'')) 
BEGIN 

IF EXISTS (SELECT 1 FROM mytesttable) BEGIN 
    SELECT ''?'' as dbname,T.A 
    FROM mytesttable AS T 
END 
END 
' 

возвращает только: db1, 1

Смежные вопросы