Tôi có thể tạo Hàm sử dụng một lần trong Tập lệnh hoặc Thủ tục được lưu trữ không?


109

Trong SQL Server 2005, có khái niệm về hàm sử dụng một lần hoặc hàm cục bộ được khai báo bên trong tập lệnh SQL hoặc Thủ tục lưu trữ không? Tôi muốn loại bỏ một số phức tạp trong tập lệnh mà tôi đang viết, nhưng nó sẽ yêu cầu có thể khai báo một hàm.

Chỉ tò mò.


có thể có một cách tốt hơn để làm những gì bạn muốn mà không cần một chức năng. có lẽ bạn nên đăng một đoạn mã mà bạn muốn chuyển thành một hàm?
DForck 42

bạn có đang tạo một hàm động để mỗi lần nó khác nhau không? nếu chức năng của bạn luôn giống nhau chỉ cần để nó trong cơ sở dữ liệu
KM.

1
Tôi đã cố gắng làm điều đó như một cách để truy vấn dễ đọc hơn. Khó có thể duy trì ý tưởng tạo ra các truy vấn lớn.
Jp_

Câu trả lời:


65

Bạn có thể gọi CREATE Functiongần đầu tập lệnh và DROP Functiongần cuối.


6
Tôi sẽ đề nghị điều này. Chỉ cần cẩn thận rằng tập lệnh của bạn đã hoàn thành; nếu nó ngừng hoạt động, bạn vẫn sẽ có chức năng trong DB.
chocojosh

6
Bạn có thể kiểm tra NẾU TỒN TẠI trước mỗi lần chạy và xóa nếu tìm thấy bất kỳ điều gì.
Adrian Godong

7
@chocojosh, điều đó sẽ ổn nếu bạn kết thúc nó trong một giao dịch. Hàm sẽ không có trong cơ sở dữ liệu nếu giao dịch ném bom.
Jeff LaFay

12
@JoelCoehoorn: điều này vẫn yêu cầu quyền ghi.
user2284570

2
Lưu ý rằng điều này sẽ không hoạt động bên trong một hàm - các chức năng tạm thời bên trong các hàm không được phép. Xem: technet.microsoft.com/en-us/library/ms191320.aspx#Restrictions
Daniel Neel

95

Bạn có thể tạo các thủ tục được lưu trữ tạm thời như:

create procedure #mytemp as
begin
   select getdate() into #mytemptable;
end

trong một tập lệnh SQL, nhưng không phải các hàm. Tuy nhiên, bạn có thể lưu trữ proc kết quả của nó trong một bảng tạm thời, sau đó sử dụng thông tin đó sau này trong tập lệnh ..


7
Đây nên là câu trả lời. Điều này thực sự là sử dụng một lần nếu chỉ kết nối phạm vi tạm thời (đơn #) và có lợi ích là tránh được các hạn chế của người dùng sql.
Todd

Sau đó nó được sử dụng như thế nào? Đó không phải là lỗi đánh máy trong tên thủ tục được sử dụng trong biểu thức select thành?
jgomo3

Tôi có thể nhận được kết quả từ quy trình được lưu trữ trong ví dụ của bạn khi tôi xóa BEGINtừ khóa và thay thế ENDtừ khóa bằng GO.
Joseph Dykstra

OP đang yêu cầu một FUNCTION tạm thời và ít nhất máy chủ SQL 2012 sẽ không cho phép # -syntax cho các hàm. Chỉ các thủ tục.
Erk

Điều đó không hoạt động trong một tập lệnh và vẫn có thể yêu cầu quyền. Để tránh các phân đoạn lặp lại, tùy chọn duy nhất mà SQL có là câu lệnh WITH.
alex.peter

25

Biểu thức Bảng thông thường cho phép bạn xác định những gì về cơ bản là dạng xem chỉ tồn tại trong phạm vi của các câu lệnh chọn, chèn, cập nhật và xóa của bạn. Tùy thuộc vào những gì bạn cần làm, chúng có thể rất hữu ích.


5
Điều này nên được chấp nhận là câu trả lời đúng. Câu trả lời được chấp nhận không phải là chủ đề an toàn.
kalyan

11
Phụ thuộc vào những gì bạn đang cố gắng làm. Tôi tìm thấy câu hỏi này vì tôi đang viết trình phân tích dữ liệu và tôi không muốn lặp lại 10 dòng MERGE VÀO 30 lần. Tôi không quan tâm đến threadsafe và CTE sẽ không hoạt động với tôi.
solipsicle

16
Tôi nghĩ câu trả lời này và những khẳng định rằng đó là câu trả lời chính xác, bỏ lỡ rằng câu hỏi đang tìm kiếm một CHỨC NĂNG tạm thời, không phải BẢNG tạm thời. Trừ khi tôi thiếu thứ gì đó (không phải là hiếm) CTE có thể so sánh với bảng tạm.
JD Dài

8
Một hàm có thể nhận đối số trong khi một CTE thì không.
Răzvan Flavius ​​Panda

4
Có nhiều điểm khác biệt giữa CTE và quy trình lưu trữ tạm thời (đó là câu trả lời chính xác ở đây IMO). Đối với người mới bắt đầu, CTE chỉ tồn tại cho một câu lệnh duy nhất, trong khi các biến tạm thời có thể được sử dụng trong toàn bộ tập lệnh. Những khác biệt khác bao gồm: (1) CTE không thể chứa cùng một logic mà một SP có thể, (2) CTE không thể chấp nhận các biến. CTE chỉ là một đường cú pháp để cho phép bạn dễ dàng xây dựng các biểu thức bảng lồng nhau để sử dụng trong một câu lệnh. Thậm chí sau đó chúng có thể nguy hiểm về mặt hiệu suất nếu bạn không biết những điều cần lưu ý.
Lopsided

12

Tôi biết tôi có thể bị chỉ trích vì đề xuất SQL động, nhưng đôi khi đó là một giải pháp tốt. Chỉ cần đảm bảo rằng bạn hiểu các tác động bảo mật trước khi xem xét điều này.

DECLARE @add_a_b_func nvarchar(4000) = N'SELECT @c = @a + @b;';
DECLARE @add_a_b_parm nvarchar(500) = N'@a int, @b int, @c int OUTPUT';

DECLARE @result int;
EXEC sp_executesql @add_a_b_func, @add_a_b_parm, 2, 3, @c = @result OUTPUT;
PRINT CONVERT(varchar, @result); -- prints '5'

4

Trong các tập lệnh, bạn có nhiều lựa chọn hơn và tốt hơn trong việc phân rã hợp lý. Xem xét chế độ SQLCMD (Menu truy vấn -> chế độ SQLCMD), cụ thể là các lệnh: setvar và: r.

Trong một quy trình được lưu trữ, các tùy chọn của bạn rất hạn chế. Bạn không thể tạo định nghĩa một hàm trực tiếp với phần thân của một thủ tục. Điều tốt nhất bạn có thể làm là như thế này, với SQL động:

create proc DoStuff
as begin

  declare @sql nvarchar(max)

  /*
  define function here, within a string
  note the underscore prefix, a good convention for user-defined temporary objects
  */
  set @sql = '
    create function dbo._object_name_twopart (@object_id int)
    returns nvarchar(517) as
    begin
      return 
        quotename(object_schema_name(@object_id))+N''.''+
        quotename(object_name(@object_id))
    end
  '

  /*
  create the function by executing the string, with a conditional object drop upfront
  */
  if object_id('dbo._object_name_twopart') is not null drop function _object_name_twopart
  exec (@sql)

  /*
  use the function in a query
  */
  select object_id, dbo._object_name_twopart(object_id) 
  from sys.objects
  where type = 'U'

  /*
  clean up
  */
  drop function _object_name_twopart

end
go

Điều này gần đúng với một hàm tạm thời toàn cục, nếu một thứ như vậy tồn tại. Nó vẫn hiển thị với những người dùng khác. Bạn có thể thêm @@ SPID của kết nối của mình để chỉ định tên duy nhất, nhưng điều đó sẽ yêu cầu phần còn lại của quy trình cũng phải sử dụng SQL động.


3

Dưới đây là những gì tôi đã sử dụng trước đây để đáp ứng nhu cầu về UDF vô hướng trong MS SQL:

IF OBJECT_ID('tempdb..##fn_Divide') IS NOT NULL DROP PROCEDURE ##fn_Divide
GO
CREATE PROCEDURE ##fn_Divide (@Numerator Real, @Denominator Real) AS
BEGIN
    SELECT Division =
        CASE WHEN @Denominator != 0 AND @Denominator is NOT NULL AND  @Numerator != 0 AND @Numerator is NOT NULL THEN
        @Numerator / @Denominator
        ELSE
            0
        END
    RETURN
END
GO

Exec ##fn_Divide 6,4

Cách tiếp cận này sử dụng một biến toàn cục cho PROCEDURE cho phép bạn sử dụng hàm không chỉ trong các tập lệnh của bạn mà còn trong các nhu cầu SQL động của bạn.

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.