Mengapa fungsi bernilai skalar perlu mengeksekusi izin daripada memilih?

15

Saya bertanya-tanya mengapa, untuk fungsi bernilai skalar, bahwa saya harus memberikan pengguna untuk mengeksekusi daripada hanya memilih?

sementara itu fungsi bernilai tabel berfungsi dengan baik hanya dengan izin atau db_datareaderkeanggotaan tertentu.

untuk lebih jelas di sini adalah contoh saya: Saya perlu pengguna yang hanya membaca izin ke database. jadi saya membuat pengguna yang dipanggil testUserdan memberikan db_datareaderkeanggotaan. kemudian saya membuat sebuah fungsi bernilai tabel bernama fn_InlineTable. Dan semuanya bagus. testUsermenjalankan SQL ini sepanjang hari

select * from dbo.fn_InlineTable

maka saya memerlukan fungsi skalar, jadi saya membuat fungsi skalar yang disebut fn_ScalarTest. testUsertidak dapat menjalankan SQL ini

Select dbo.fn_ScalarTest(1) 

Yah dimengerti: itu karena saya belum memberikan izin "testUser" untuk dieksekusi fn_ScalarTest.

Pertanyaan saya adalah: berdasarkan tautan ini /programming/6150888/insert-update-delete-with-function-in-sql-server , yang mengatakan bahwa FUNCTIONtidak dapat digunakan untuk melakukan tindakan yang mengubah keadaan basis data . Jadi mengapa tidak membiarkan fungsi skalar digunakan dengan izin "SELECT" yang sama daripada menjalankan izin ??

Saya harap pertanyaan saya masuk akal. Terima kasih.

BobNoobGuy
sumber

Jawaban:

15

Kemungkinan besar alasan utamanya adalah Fungsi Table-Valued mengembalikan Set Hasil, sama seperti Tabel dan Tampilan. Ini berarti bahwa mereka dapat digunakan dalam FROMayat (termasuk JOINs dan APPLYs, dll) dari SELECT, UPDATE, dan DELETEquery. Anda tidak bisa, bagaimanapun, menggunakan Scalar UDF dalam konteks apa pun itu.

Kedua, Anda juga bisa EXECUTEmenggunakan UDF Skalar. Sintaks ini cukup berguna ketika Anda memiliki nilai default yang ditentukan untuk parameter input. Ambil UDF berikut, misalnya:

CREATE FUNCTION dbo.OptionalParameterTest (@Param1 INT = 1, @Param2 INT = 2)
RETURNS INT
AS
BEGIN
    RETURN @Param1 + @Param2;
END;

Jika Anda ingin memperlakukan salah satu parameter input sebagai "opsional", Anda masih harus memasukkan DEFAULTkata kunci saat memanggilnya seperti fungsi karena tanda tangan diperbaiki:

DECLARE @Bob1 INT;

SET @Bob1 = dbo.OptionalParameterTest(100, DEFAULT);

SELECT @Bob1;
-- Returns: 102

Di sisi lain, jika Anda EXECUTEberfungsi, maka Anda dapat memperlakukan parameter apa pun dengan nilai default sebagai benar-benar opsional, sama seperti yang Anda bisa dengan Prosedur Tersimpan. Anda dapat memasukkan n parameter pertama tanpa menentukan nama parameter:

DECLARE @Bob2 INT;

EXEC @Bob2 = dbo.OptionalParameterTest 50;

SELECT @Bob2;
-- Returns: 52

Anda bahkan dapat melewati parameter pertama dengan menentukan nama parameter, sekali lagi, sama seperti dengan Prosedur Tersimpan:

DECLARE @Bob3 INT;

EXEC @Bob3 = dbo.OptionalParameterTest @Param2 = 50;

SELECT @Bob3;
-- Returns: 51

MEMPERBARUI

Mengapa Anda ingin menggunakan EXECsintaks untuk memanggil skalar UDF seperti Prosedur yang Disimpan? Kadang-kadang ada UDF yang bagus untuk dimiliki sebagai UDF karena mereka dapat ditambahkan ke kueri dan beroperasi di atas set baris yang dikembalikan, sedangkan jika kode berada dalam Prosedur Tersimpan maka perlu ditempatkan ke dalam kursor untuk beralih pada satu set baris. Tetapi kemudian ada saat-saat Anda ingin memanggil fungsi itu pada nilai tunggal, mungkin dari dalam UDF lain. Memanggil UDF untuk nilai tunggal dapat dilakukan sebagai:

SELECT dbo.UDF('some value');

dalam hal ini Anda mendapatkan nilai kembali di set hasil (set hasil tidak akan berfungsi). Atau bisa juga dilakukan sebagai berikut:

DECLARE @Dummy INT;

SET @Dummy = dbo.UDF('some value');

dalam hal ini Anda perlu mendeklarasikan @Dummyvariabel;

NAMUN, dengan EXECsintaks, Anda dapat menghindari kedua gangguan tersebut:

EXEC dbo.UDF 'some value';

JUGA, skalar UDF memiliki rencana eksekusi yang di-cache. Ini berarti bahwa ada kemungkinan untuk mengalami masalah sniffing parameter jika ada pertanyaan di UDF yang memiliki rencana eksekusi. Untuk skenario di mana layak untuk menggunakan EXECsintaks, maka dimungkinkan untuk juga menggunakan WITH RECOMPILEopsi untuk mengabaikan rencana nilai yang dikompilasi untuk eksekusi itu . Sebagai contoh:

MEMPERSIAPKAN:

GO
CREATE FUNCTION dbo.TestUDF (@Something INT)
RETURNS INT
AS 
BEGIN
   DECLARE @Ret INT;
   SELECT @Ret = COUNT(*)
   FROM   sys.indexes si
   WHERE  si.[index_id] = @Something;

   RETURN @Ret;
END;
GO

UJI:

DECLARE @Val INT;

SET @Val = dbo.TestUDF(1);
SELECT @Val;

EXEC @Val = dbo.TestUDF 0 -- uses compiled value of (1)
SELECT @Val;

EXEC @Val = dbo.TestUDF 0 WITH RECOMPILE; -- uses compiled value of (0)
SELECT @Val;

EXEC @Val = dbo.TestUDF 3 -- uses compiled value of (1)
SELECT @Val;
Solomon Rutzky
sumber
4

Saya pikir perbedaan dalam izin adalah karena Anda benar-benar dapat menjalankan fungsi yang ditentukan pengguna dengan skalar dengan EXEC seperti prosedur tersimpan (yang belum saya sadari sampai saya menggali SQL Server 2000 Books Online, di mana mereka memperkenalkan fungsi yang ditentukan pengguna) , namun Anda tidak dapat benar-benar memilih dari mereka sebagai sumber tabel. Sebagai contoh:

DECLARE @date datetime
EXEC @date = dbo.first_day_of_month '8/14/2015'
SELECT @date

Dalam hal ini, dbo.first_day_of_month adalah fungsi yang ditentukan pengguna. Saya tidak tahu mengapa Anda akan menjalankan fungsi seperti itu, tetapi saya berspekulasi bahwa mereka memerlukan izin EXECUTE daripada SELECT untuk mempertahankan konsistensi. Saat ini mungkin hanya bertahan sebagai bagasi kompatibilitas.

db2
sumber