Kiedy uruchamiam następujący skrypt, działa dobrze:

declare @temp table ( name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255) ); INSERT @temp exec sp_msforeachdb @command1="use ?; Exec sp_helpfile;" 

ale kiedy Używam własnej procedury sp_foreachdb, kod źródłowy znajduje się pod poniższym linkiem:

Bardziej niezawodny i elastyczny sp_MSforeachdb

declare @temp table ( name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255) ); INSERT @temp exec sp_foreachdb @command="use ?; Exec sp_helpfile;" 

Otrzymałem wyjątek (pamiętaj, że dodałem obsługę wyjątków w tej procedurze)

--EXCEPTION WAS CAUGHT-- THE ERROR NUMBER:8164 SEVERITY: 16 STATE: 1 PROCEDURE: sp_foreachdb LINE NUMBER: 165 ERROR MESSAGE: An INSERT EXEC statement cannot be nested. ------------------------------------ the sql ------------------------------------ SELECT name FROM sys.databases WHERE 1=1 AND state_desc = N"ONLINE" AND is_read_only = 0 Msg 16916, Level 16, State 1, Procedure sp_foreachdb, Line 239 A cursor with the name "c" does not exist. Msg 16916, Level 16, State 1, Procedure sp_foreachdb, Line 240 A cursor with the name "c" does not exist. (0 row(s) affected) 

Komentarze

  • ' Nie wiem, dlaczego ' ponownie używasz tego zawiłego metoda. Dlaczego nie po prostu zapytać sys.master_files?
  • @Nic dobrze wskazał, jednak właśnie użyłem sp_helpfile jako przykładu. w rzeczywistości jest to jedna z naszych własnych procedur składowanych, którą chciałbym wywołać

Odpowiedź

Kod źródłowy dla Aarona „s sp_foreachdb zawiera następujący wiersz:

INSERT #x EXEC sp_executesql @sql;

Zgodnie z Twoim komunikat o błędzie:

Instrukcja INSERT EXEC nie może być zagnieżdżona.

Więc poniższy kod nie będzie prawidłowy, ponieważ jest zagnieżdżony kod INSERT xxx EXEC xxx.

INSERT @temp exec sp_msforeachdb @command1="use ?; Exec sp_helpfile;" 

Komentarze

  • @marcellomiorelli Myślę, że wymagałoby to dużej zmiany na SP Aarona ' s, aby usunąć dynamiczny SQL. Prawdopodobnie wymagałoby to użycia dodatkowa funkcja.

Odpowiedź

Połączenie z własnym serwerem za pomocą rozproszonych metod zapytań załatwi sprawę, jeśli sp_foreachdb zwróci pojedynczy zestaw wyników.

create table #temp ( name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255) ); insert into #temp select * FROM OPENROWSET("SQLNCLI", "SERVER=****;UID=****;PWD=****", " exec sp_foreachdb @command="" Exec ?..sp_helpfile;"" WITH RESULT SETS ((name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255))); ") select * from #temp 

powyżej zapytania w źle zwróci tylko pierwszy zestaw wyników wykonania sp_foreachdb. ale poniżej zapytanie zwróci wynik dla wszystkich baz danych w jednym zestawie wyników.

create table #temp ( name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255) ); exec sp_foreachdb @command="INSERT INTO #temp Exec ?..sp_helpfile;" select * from #temp 

Odpowiedź

Możesz spróbować dostosować SP Aarona, pozbywając się części dynamicznej. Część dynamiczna ma na celu zbudowanie zapytania odczytującego tylko nazwy baz danych z sys.databases na podstawie dostarczonych argumentów. Dynamiczny SQL jest wybierany, aby uczynić zapytanie najbardziej wydajnym – jak również do utrzymania. Biorąc pod uwagę twoje specyficzne potrzeby, niektóre wyrzeczenia mogą być w porządku.

Twierdzę jednak, że wydajność może nie ucierpieć zbytnio z powodu przepisania, które oferuję poniżej, ponieważ sys.databases widok systemu zwykle nie ma zbyt wielu wierszy, ale w każdym razie możesz dodać na końcu OPTION (RECOMPILE). Jakkolwiek wolno to może być, chociaż prawdopodobnie skończy się raczej brzydko, co mogę obiecać.

Metoda przepisywania jest następująca. Procedura Aarona polega na budowaniu zapytania przy użyciu powtarzającego się wzorca, w którym sprawdzana jest wartość parametru i , na podstawie wyniku, dodatkowy zapytanie jest dodawane do dynamicznego zapytania, np. w ten sposób:

SET @sql = N"SELECT name FROM sys.databases WHERE 1=1" + CASE WHEN some_condition1 THEN "AND some_filter1" ELSE "" END + CASE WHEN some_condition2 THEN "AND some_filter2" ELSE "" END + ... 

Oto jak można to przepisać:

SELECT name FROM sys.databases WHERE 1=1 AND (some_filter1 OR opposite_of_some_condition1) AND (some_filter2 OR opposite_of_some_condition2) AND ... OPTION (RECOMPILE); 

Na przykład @system_only określa, czy filtr database_id IN (1,2,3,4) powinien zostać uwzględniony, na przykład:

SET @sql = N"SELECT name FROM sys.databases WHERE 1=1" + CASE WHEN @system_only = 1 THEN " AND database_id IN (1,2,3,4)" ELSE "" END 

Przepisane zapytanie byłoby sparametryzowane w następujący sposób:

SELECT name FROM sys.databases WHERE 1=1 AND (database_id IN (1,2,3,4) OR @system_only <> 1) -- or: @system_only = 0 

Użyj wynikowego zapytania w kursor bezpośrednio, zamiast

 SELECT CASE WHEN @suppress_quotename = 1 THEN db ELSE QUOTENAME(db) END FROM #x ORDER BY db 

Jak widać, ostatnie dotknięcie musiałoby przejść do części SELECT, gdzie proste SELECT name nowego zapytania zostanie zastąpione przez

 SELECT CASE WHEN @suppress_quotename = 1 THEN name ELSE QUOTENAME(name) END 

Oczywiście możesz teraz również pozbyć się #x tabela, która nie jest już potrzebna w SP.

Ostatnia uwaga dotyczy konkretnego skryptu, który planujesz uruchomić na każdej bazie danych. Zamiast

@command1="use ?; Exec sp_helpfile;" 

mógłbyś mieć po prostu

@command1="Exec ?..sp_helpfile;" 

Odpowiedź

Napisałem zamiennik, który ma kilka ulepszeń w stosunku do oryginalnego sp_foreachdb , w tym możliwość zagnieżdżania. Nowsza, preferowana procedura nosi nazwę sp_ineachdb ( część 1 / część 2 ) i jest również dostępny jako część zestawu ratunkowego Brenta Ozara .

Trochę informacji ogólnych tutaj :

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *