Tạo chức năng mới bằng mã nếu nó không tồn tại


15

Tôi muốn tạo chức năng mới theo kịch bản trong cơ sở dữ liệu của tôi. Mã script bên dưới:

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

Nhưng khi tôi thực thi đoạn mã trên, SQL Server sẽ trả về lỗi:

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

Câu trả lời:


16

Cập nhật tháng 1 năm 2017 - SQL Server 2016+ / Cơ sở dữ liệu SQL Azure

SQL Server 2016 và phiên bản hiện tại của Azure SQL Database hiện có cú pháp sau cho các chức năng, quy trình, bảng, cơ sở dữ liệu, v.v. ( DROP IF EXISTS):

DROP FUNCTION IF EXISTS dbo.fn_myfunc;

Và SQL Server 2016 Gói dịch vụ 1 bổ sung thêm chức năng tốt hơn cho các mô-đun (chức năng, quy trình, trình kích hoạt, chế độ xem) có nghĩa là không mất quyền hoặc phụ thuộc ( CREATE OR ALTER):

CREATE OR ALTER FUNCTION dbo.fn_myfunc ...

Cả hai cải tiến cú pháp này có thể dẫn đến các tập lệnh đơn giản hơn nhiều được sử dụng để kiểm soát nguồn, triển khai, v.v.

Nhưng, nếu bạn đang sử dụng ...


Các phiên bản cũ hơn

Bạn cần làm những gì SQL Server làm khi bạn viết kịch bản này từ Management Studio:

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

Hoặc bạn có thể nói:

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

Hoặc bạn chỉ có thể nói:

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

(Ở đây bạn sẽ nhận được thông báo lỗi nếu hàm không tồn tại, nhưng tập lệnh sẽ tiếp tục từ GO tiếp theo, do đó, liệu thả có hoạt động hay không, hàm vẫn sẽ được tạo lại.)

Lưu ý rằng nếu bạn bỏ chức năng và tạo lại chức năng đó, bạn cũng sẽ mất quyền và thông tin phụ thuộc tiềm năng.


1
vì vậy không có từ khóa $$ TẠO HOẶC THAY THẾ $$? điều đáng tiếc.
zinking

@zinking không, nhưng có thể trong một phiên bản trong tương lai. Vui lòng bỏ phiếu / nhận xét: connect.microsoft.com/QueryServer/feedback/details/127219/NH
Aaron Bertrand

1
@AaronBertrand Ý tưởng tốt để bỏ phiếu cho nó, nhưng liên kết bị hỏng
màu xanh lam

@bluish vâng xin lỗi, họ loại bỏ các đôi khi mục giữa ba năm trước, khi tôi đăng các liên kết và bây giờ ... Hãy thử connect.microsoft.com/SQLServer/feedback/details/344991/... hoặc connect.microsoft.com/SQLServer/feedback / chi tiết / 351217 / Hoài
Aaron Bertrand

Điều này có thể có sẵn ngay bây giờ: blog.msdn.microsoft.com/sqlserverst Storageengine / 2016/11/17 / Kẻ
Bruno

1

Các lỗi là khá tự giải thích. Có một vài cách để sửa nó.

  1. Phân tách tập lệnh thành các lô khác nhau trong Management Studio bằng cách sử dụng GOtừ khóa giả và DROP/ CREATEđối tượng. (Lưu ý rằng chính từ khóa có thể được thay đổi trong tùy chọn Studio quản lý, nhưng đây là cài đặt thực tế, vì vậy tôi khuyên bạn nên để nó một mình).

    Khi bạn chạy tập lệnh (hoặc phần được chọn của tập lệnh), Management Studio sẽ tách từng đoạn tập lệnh giữa GOcác s và gửi tuần tự các phần cho SQL Server thành các lô riêng biệt.

  2. Sử dụng SQL động để gửi một lô riêng từ trong một lô khác.

    Đây là phương pháp ưa thích, bởi vì sau đó tập lệnh của bạn không phụ thuộc vào chức năng bên ngoài để thực thi chính xác. Ví dụ: nếu ứng dụng của bạn có chương trình cập nhật cơ sở dữ liệu, nói chung, nó sẽ tải tệp tập lệnh và sau đó thực thi nó trên máy chủ đích. Bạn sẽ phải thêm logic để phân tách các lô như Management Studio thực hiện (lưu ý: đầy rủi ro) hoặc viết tập lệnh theo cách mà toàn bộ tập lệnh có thể được thực thi thành công như một lô.

    Như đã đề cập trong câu trả lời khác, bạn có thể thực hiện kiểm tra / CREATEsử dụng phương pháp này (hoặc một số kết hợp khác của DROP/ CREATE, v.v.). Những gì tôi thích làm là tạo một đối tượng còn sơ khai nếu đối tượng không tồn tại, và sau đó sử dụng ALTER <object>để thực sự tạo hoặc thay đổi. Cách tiếp cận này không bỏ các phụ thuộc, chẳng hạn như quyền hoặc thuộc tính mở rộng và không cần sao chép / dán logic dễ bị lỗi để thực hiện CREATE/ ALTERtrong một câu lệnh.

    Đây là mẫu tôi sử dụng để tạo hoặc thay đổi hàm vô hướng. Tôi sẽ để nó như một bài tập để người đọc thích ứng điều này với các loại đối tượng khác (lưu trữ procs, kích hoạt, v.v.).

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>]
/* ... */
'

Làm thế nào có thể tùy chọn 1 làm việc ở đây? Thêm một GOthực sự đảm bảo kịch bản sẽ phá vỡ, vì IFsẽ không dẫn đến đâu.
Aaron Bertrand

@Aaron: Tôi đã nghĩ đến DROP/ CREATEkịch bản - được chỉnh sửa. Cảm ơn.
Jon Seigel

1

Bạn có tùy chọn kiểm tra nếu đối tượng tồn tại trong databasevà tạo nếu không:

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

...
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.