NOTA PARA OS LEITORES: Leia a pergunta inteira, incluindo o código de exemplo (ou seja, não apenas o título). Esta pergunta não é sobre como melhor percorrer os bancos de dados, nem sobre por que [tempdb] recebe esse erro. O OP já está tentando evitar executar as ALTER
instruções em todos os bancos de dados do sistema (bem, os 4 visíveis) e está perguntando por que a instrução IF que deveria estar pulando [tempdb] parece não estar pulando.
Por que o script a seguir fornece um erro relacionado ao tempdb?
O motivo é que a IF
instrução afeta apenas o que acontece quando o código está realmente em execução, mas o SQL Server ainda precisa analisar e compilar o lote antes de executá-lo. Os erros de análise são aqueles relacionados à sintaxe, como garantir que as instruções SQL sejam formadas corretamente e que as variáveis tenham sido declaradas corretamente:
-- parse the following by hitting Control-F5 or clicking the check mark in SSMS
SELECT @Bob;
obtém o seguinte erro:
Msg 137, Level 15, State 2, Line 2
Must declare the scalar variable "@Bob".
E o seguinte:
-- parse the following by hitting Control-F5 or clicking the check mark in SSMS
CREATE TABLE b
obtém o seguinte erro:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'b'.
Se o lote for analisado com êxito, ele será compilado. Nesse momento, coisas como permissões são verificadas e outras verificações são executadas.
-- parse the following by hitting Control-F5 or clicking the check mark in SSMS
IF (1 = 0)
BEGIN
ALTER AUTHORIZATION ON DATABASE::[tempdb] TO [sa];
ALTER DATABASE [tempdb] SET RECOVERY SIMPLE;
END;
O SQL acima é formado corretamente para que o lote seja analisado com êxito. Agora tente executar o SQL acima pressionando F5 ou Control-E ou o ! Botão Executar , etc.
Dessa vez, você recebe o seguinte erro:
Msg 5058, Level 16, State 1, Line 4
Option 'RECOVERY' cannot be set in database 'tempdb'.
mesmo que IF (1 = 0)
isso garanta que o código nunca seja executado. Isso significa que você está executando um erro de compilação. Você pode contornar esses tipos de erros movendo o código incorreto para um subprocesso por meio de uma EXEC
chamada.
Execute o seguinte e ele será concluído com êxito, pois o que está dentro dele EXEC()
não é analisado ou compilado até que a instrução seja executada em tempo de execução.
IF (1 = 0)
BEGIN
EXEC('
ALTER AUTHORIZATION ON DATABASE::[tempdb] TO [sa];
ALTER DATABASE [tempdb] SET RECOVERY SIMPLE;
');
END;
Para resumir:
Primeiro, considere que sp_MSForEachDB
percorre os bancos de dados e executa o SQL passado após a substituição pelo ?
nome atual do banco de dados. Portanto, quando o cursor dentro de sp_MSForEachDB
chegar [tempdb]
, ele efetivamente faz o seguinte:
IF ( (select database_id from sys.databases where name = ''tempdb'') > 4)
BEGIN
ALTER AUTHORIZATION ON DATABASE::tempdb TO [sa];
ALTER DATABASE [tempdb] SET RECOVERY SIMPLE;
END
Segundo, há várias etapas que o SQL Server executa quando você executa um lote de consulta:
- Analisar
- Compilar
- Execução real
É importante entender que essas são etapas separadas e podem gerar erros antes de prosseguir para a próxima etapa (e, portanto, cancelar o processamento adicional antes de prosseguir para a próxima etapa). No caso aqui, o erro está ocorrendo na Etapa 2 - Compilar - conforme comprovado no segundo ao último exemplo acima (o primeiro a começar IF (1 = 0)
). Os IF (1 = 0)
impede a dentro do código do BEGIN...END
bloco de sempre correndo, mas o erro ainda ocorrer. Portanto, o erro não está ocorrendo devido a uma tentativa real de executar as duas ALTER
instruções.
O motivo pelo qual agrupar as ALTER
instruções dentro da EXEC()
função funciona é porque o SQL Server não analisará e compilará o que está dentro dele EXEC()
até que ele EXEC()
esteja realmente em execução. Nesse ponto, a IF ( (select database_id from sys.databases where name = ''?'') > 4)
instrução poderá ser executada, pois o lote não falhará durante a Compilação e chegará à Execução. A IF
instrução será ignorada [tempdb]
e o erro "Opção 'RECUPERAÇÃO' não pode ser definido no banco de dados 'tempdb'" não irá ocorrer.
IF
instrução nem nenhuma outra instrução SQL (incluindo as duasALTER
) estão sendo executadas neste momento. AIF
instrução não está permitindo que o ID do tempdb seja enviado para o que está dentro do blocoBEGIN
/END
, e o código nem está executando asALTER
instruções neste momento. O erro está sendo gerado pelo SQL Server, pois está validando o SQL antes de executá-lo. Eu adicionei uma seção de resumo ao final.Primeiro de tudo, não há necessidade de usar o
ms_foreachdb
seu documento não documentado e o quão ruim você pode usar o cursor simples. Em relação ao erro, você está tentando alterar o modelo de recuperação de todos os bancos de dados,including tempdb
mas não pode alterar o modelo de recuperação do tempdb, nem executar nenhuma operação de backup, por isso recebeu esta mensagem de erro. Isso não é permitido pela Microsoft. Leia mais sobre as operações que você pode realizar no tempdbfonte
ALTER
instruções estão apenas sendo validadas , não executadas. Eu forneço detalhes na minha resposta .Além do fato de você não poder alterar a opção de recuperação para o tempdb, você não precisa de um loop para o que está fazendo:
Execute no SSMS pressionando CTRL+T
fonte