it-swarm-eu.dev

Vytvořte novou funkci pomocí kódu, pokud neexistuje

Chci vytvořit novou funkci skriptem v mé databázi. Kód skriptu je níže:

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

Ale když spustím výše uvedený skript, SQL Server vrátí chybu:

'CREATE FUNCTION' must be the first statement in a query batch.
15
mehdi lotfi

Aktualizace leden 2017 - SQL Server 2016+/Azure SQL Database

SQL Server 2016 a aktuální verze Azure SQL Database má nyní následující syntaxi pro funkce, procedury, tabulky, databáze atd. ( DROP IF EXISTS ):

DROP FUNCTION IF EXISTS dbo.fn_myfunc;

A SQL Server 2016 Service Pack 1 přidává ještě lepší funkčnost pro moduly (funkce, procedury, spouštěče, zobrazení), což znamená, že nedochází ke ztrátě oprávnění nebo závislostí ( CREATE OR ALTER ):

CREATE OR ALTER FUNCTION dbo.fn_myfunc ...

Obě tato vylepšení syntaxe mohou vést k mnohem jednodušším skriptům používaným pro řízení zdroje, nasazení atd.

Ale pokud používáte ...


Starší verze

Při skriptu z Management Studio je třeba udělat to, co SQL Server dělá:

IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE type = 'FN' AND name = 'fn_myfunc')
BEGIN
    DECLARE @sql NVARCHAR(MAX);
    SET @sql = N'CREATE FUNCTION ...';
    EXEC sp_executesql @sql;
END

Nebo můžete říct:

BEGIN TRY
    DROP FUNCTION dbo.fn_myfunc;
END TRY
BEGIN CATCH
    PRINT 'Function did not exist.';
END CATCH
GO
CREATE FUNCTION...

Nebo můžete jen říct:

DROP FUNCTION dbo.fn_myfunc;
GO
CREATE FUNCTION...

(Zde se zobrazí chybová zpráva, pokud funkce již neexistuje, ale skript bude pokračovat od příštího GO, takže ať už kapka pracovala nebo ne, bude funkce stále vytvořena (znovu).)

Pokud funkci zrušíte a znovu ji vytvoříte, ztratíte také oprávnění a informace o závislostech.

17
Aaron Bertrand

Máte možnost zkontrolovat, zda objekt existuje v database a pokud ne, vytvořit:

IF OBJECT_ID('new_function', 'FN') IS NULL
BEGIN
  EXEC('CREATE FUNCTION new_function() RETURNS INT AS BEGIN RETURN 1 END');
END;
go

ALTER FUNCTION new_function() RETURNS INT AS
BEGIN

...
2
Sorack

Tato chyba je docela samozřejmá. Existuje několik způsobů, jak to opravit.

  1. Rozdělte skript do různých šarží v Management Studio pomocí pseudo-klíčového slova GO a DROP/CREATE objekt. (Všimněte si, že samotné klíčové slovo lze změnit v možnostech Management Studio, ale toto je faktické nastavení, takže navrhuji ponechat jej na pokoji).

    Při spuštění skriptu (nebo vybrané části skriptu) Management Studio odděluje každý kus skriptu mezi GO s a postupně odešle části na SQL Server jako samostatné šarže.

  2. Použijte dynamický SQL k odeslání samostatné dávky zv rámci jiné dávky.

    Toto je upřednostňovaná metoda, protože pak váš skript nezávisí na správném provedení externí funkce. Například, pokud má vaše aplikace program aktualizace databáze, obecně řečeno, načte soubor skriptu a poté jej provede na cílovém serveru. Buď budete muset přidat logiku k oddělení dávek jako Management Studio (poznámka: plná nebezpečí), nebo napsat skript tak, aby celý lze skript úspěšně spustit jako jednu dávku.

    Jak je uvedeno v jiné odpovědi, můžete pomocí této metody provést test/CREATE (nebo jinou kombinaci DROP/CREATE atd.). Co raději dělám, je vytvořit objekt se zakázaným inzerováním, pokud objekt neexistuje, a poté použít ALTER <object>, aby skutečně vytvořil nebo změnil. Tento přístup nezruší závislosti, například oprávnění nebo rozšířené vlastnosti, a není nutné kopírovat/vložit logiku náchylnou k chybám, aby bylo možné provést CREATE/ALTER v jediném příkazu.

    Zde je šablona, ​​kterou používám pro vytváření nebo změnu skalární funkce. Nechám to jako cvičení pro čtenáře, aby to přizpůsobil jiným typům objektů (uložené proci, triggery atd.).

IF NOT EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[<schema>].[<function name>]') AND type IN ('FN', 'FS'))
    EXEC sp_executesql N'CREATE FUNCTION [<schema name>].[<function name>] (@a int) RETURNS int AS BEGIN /* Stub */ RETURN @a END'

EXEC sp_executesql N'
ALTER FUNCTION [<schema name>].[<function name>]
/* ... */
'
1
Jon Seigel