Eu quero criar uma nova função por script no meu banco de dados. O código do script está abaixo:
IF Exists(Select * From sys.sysobjects A Where A.name =N'fn_myfunc' and xtype=N'FN') return;
CREATE FUNCTION fn_myfunc ()
returns varchar(10)
AS Begin
...
End
Mas quando executo o script acima, o SQL Server retorna um erro:
'CREATE FUNCTION' must be the first statement in a query batch.
Atualização de janeiro de 2017 - SQL Server 2016+ / Banco de Dados SQL do Azure
O SQL Server 2016 e a versão atual do Banco de Dados SQL do Azure agora possuem a seguinte sintaxe para funções, procedimentos, tabelas, bancos de dados etc. (
DROP IF EXISTS
):E o SQL Server 2016 Service Pack 1 adiciona funcionalidades ainda melhores para módulos (funções, procedimentos, gatilhos, exibições), o que significa que não há perda de permissões ou dependências (
CREATE OR ALTER
):Ambos os aprimoramentos de sintaxe podem levar a scripts muito mais simples usados para controle de origem, implantações etc.
Mas se estiver usando...
versões mais antigas
Você precisa fazer o que o SQL Server faz ao criar um script no Management Studio:
Ou você pode dizer:
Ou você pode simplesmente dizer:
(Aqui você receberá uma mensagem de erro se a função ainda não existir, mas o script continuará a partir do próximo GO, portanto, se a queda funcionou ou não, a função ainda será (re-)criada.)
Observe que, se você descartar a função e recriá-la, também perderá permissões e informações de dependência potencialmente.
Você tem a opção de verificar se o objeto existe no
database
e criar se não existir:O erro é bastante autoexplicativo. Existem algumas maneiras de corrigi-lo.
Separe o script em lotes diferentes no Management Studio usando a
GO
pseudo-palavra-chave eDROP
/CREATE
o objeto. (Observe que a própria palavra-chave pode ser alterada nas opções do Management Studio, mas essa é a configuração de fato, então sugiro deixá-la em paz).Quando você executa um script (ou a parte selecionada de um script), o Management Studio separa cada parte do script entre
GO
s e envia sequencialmente as partes para o SQL Server como lotes separados.Use SQL dinâmico para enviar um lote separado de outro lote.
Este é o método preferencial, pois seu script não depende de funcionalidades externas para ser executado corretamente. Por exemplo, se sua aplicação possui um programa de atualização de banco de dados, de modo geral, ele carregará um arquivo de script e o executará no servidor de destino. Ou você terá que adicionar lógica para separar os lotes como o Management Studio faz (nota: cheio de perigos), ou escrever o script de forma que todo o script possa ser executado com sucesso como um único lote.
Como mencionado em outra resposta, você pode fazer um teste/
CREATE
usando este método (ou alguma outra combinação deDROP
/CREATE
, etc.). O que eu prefiro fazer é criar um objeto stub se o objeto não existir, e então usarALTER <object>
para realmente fazer a criação ou alteração. Essa abordagem não elimina dependências, como permissões ou propriedades estendidas, e não é necessário copiar/colar lógica propensa a erros para fazerCREATE
/ALTER
em uma única instrução.Aqui está o modelo que uso para criar ou alterar uma função escalar. Vou deixar como exercício para o leitor adaptar isso para outros tipos de objetos (procs armazenados, triggers, etc.).