quando executo o seguinte script, ele funciona bem:

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;" 

mas quando Eu uso meu próprio procedimento sp_foreachdb, o código-fonte está neste link abaixo:

Um sp_MSforeachdb mais confiável e flexível

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;" 

Recebo uma exceção (observe que adicionei o tratamento de exceções a esse procedimento)

--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) 

Comentários

  • Eu ‘ não tenho certeza por que você ‘ está usando este complicado método. Por que não apenas consultar sys.master_files?
  • @Nic bem apontado, entretanto, acabei de usar o sp_helpfile como exemplo. na vida real, é um de nossos próprios procedimentos armazenados que eu chamaria

Resposta

O código-fonte para Aaron “s sp_foreachdb contém a seguinte linha:

INSERT #x EXEC sp_executesql @sql;

De acordo com seu mensagem de erro:

Uma instrução INSERT EXEC não pode ser aninhada.

Então código como o abaixo não será válido, pois está aninhando o código INSERT xxx EXEC xxx.

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

Comentários

  • @marcellomiorelli Acho que seria necessária uma grande mudança no SP de Aaron ‘ s para remover o SQL dinâmico. Isso provavelmente exigiria o uso de uma função adicional.

Resposta

Conectar-se ao seu próprio servidor por meio de métodos de consulta distribuída resolveria o problema se sp_foreachdb retornaria conjunto de resultados único.

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 

acima da consulta w Vou retornar apenas o primeiro conjunto de resultados da execução de sp_foreachdb. mas a consulta abaixo retornará o resultado de todos os bancos de dados em um único conjunto de resultados.

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 

Resposta

Você poderia tentar adaptar o SP de Aaron livrando-se de sua parte dinâmica. A parte dinâmica deve construir uma consulta lendo apenas os nomes do banco de dados de sys.databases com base nos argumentos fornecidos. O SQL dinâmico é escolhido para tornar a consulta mais eficiente – bem como de manutenção. Levando em consideração suas necessidades específicas, alguns sacrifícios podem ser necessários.

Eu argumentaria, porém, que o desempenho pode não sofrer muito com a reescrita que estou oferecendo abaixo, como o sys.databases a visualização do sistema geralmente não tem muitas linhas, mas em qualquer caso, você pode adicionar OPTION (RECOMPILE) no final. Por mais lento que seja, entretanto, é provável que termine bastante feio, isso eu posso prometer.

O método de reescrever é o seguinte. O procedimento de Aaron é construir a consulta usando um padrão de repetição onde um valor de parâmetro é verificado e , com base no resultado, um adicional a consulta é adicionada à consulta dinâmica, isto é:

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 + ... 

Aqui está como você reescreveria isso:

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); 

Por exemplo, o @system_only controla se o database_id IN (1,2,3,4) filtro deve ser incluído, como este:

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 

A consulta reescrita seria parametrizada desta forma:

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

Use a consulta resultante em o cursor diretamente, em vez de

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

Como pode ser visto, o toque final precisaria ir para a parte SELECT, onde o da nova consulta seria substituído por

Obviamente, agora você também pode se livrar do #x tabela como não é mais necessária no SP.

Uma última observação diz respeito ao script específico que você está planejando executar em cada banco de dados. Em vez de

@command1="use ?; Exec sp_helpfile;" 

você poderia ter apenas

@command1="Exec ?..sp_helpfile;" 

Resposta

Escrevi uma substituição que tem várias melhorias em relação ao original sp_foreachdb , incluindo a capacidade de aninhar. O procedimento preferido mais recente é chamado de sp_ineachdb ( parte 1 / parte 2 ) e também está disponível como parte do Brent Ozar “s Kit de primeiros socorros .

Algumas informações aqui :

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *