ทำไมฟังก์ชันอันทรงคุณค่าของสเกลาร์ต้องได้รับอนุญาตให้ดำเนินการแทนที่จะเลือก


15

ฉันสงสัยว่าเพราะเหตุใดสำหรับฟังก์ชันที่มีค่าสเกลาร์ฉันต้องให้ผู้ใช้ดำเนินการแทนที่จะเลือกเท่านั้น?

ในขณะที่ฟังก์ชั่นที่มีคุณค่าของตารางนั้นใช้งานได้ดีโดยมีเพียงสิทธิ์อนุญาตหรือความdb_datareaderเป็นสมาชิกที่เลือกเท่านั้น

เพื่อให้ชัดเจนยิ่งขึ้นนี่คือตัวอย่างของฉัน: ฉันต้องการผู้ใช้ที่ได้รับอนุญาตให้อ่านฐานข้อมูลเท่านั้น ดังนั้นฉันจึงสร้างผู้ใช้ที่เรียกว่าtestUserและให้การdb_datareaderเป็นสมาชิก fn_InlineTableแล้วฉันสร้างตารางมูลค่าฟังก์ชั่นที่เรียกว่า และทุกอย่างยอดเยี่ยม testUserรัน SQL นี้ตลอดทั้งวัน

select * from dbo.fn_InlineTable

fn_ScalarTestแล้วฉันต้องมีฟังก์ชั่นเกลาดังนั้นฉันสร้างฟังก์ชั่นที่เรียกว่าสเกลา testUserไม่สามารถรัน SQL นี้

Select dbo.fn_ScalarTest(1) 

ดีเข้าใจ: มันเป็นเพราะผมยังไม่ได้ให้ "testuser" fn_ScalarTestได้รับอนุญาตในการดำเนินการ

คำถามของฉันคือ: ตามลิงค์นี้/programming/6150888/insert-update-delete-with-function-in-sql-serverซึ่งบอกว่าFUNCTIONไม่สามารถใช้เพื่อดำเนินการแก้ไขสถานะฐานข้อมูลได้ . ดังนั้นทำไมไม่ปล่อยให้ฟังก์ชั่นสเกลาร์ถูกใช้ด้วยสิทธิ์ "SELECT" แบบเดียวกันแทนที่จะเรียกใช้สิทธิ์ ???

ฉันหวังว่าคำถามของฉันจะสมเหตุสมผล ขอขอบคุณ.

คำตอบ:


15

ส่วนใหญ่เหตุผลหลักคือฟังก์ชั่นที่ประเมินค่าตารางจะส่งคืนชุดผลลัพธ์เช่นเดียวกับตารางและมุมมอง ซึ่งหมายความว่าพวกเขาสามารถนำมาใช้ในFROMประโยค (รวมถึงJOINและAPPLYS, ฯลฯ ) ของSELECT, UPDATEและDELETEคำสั่ง อย่างไรก็ตามคุณไม่สามารถใช้ Scalar UDF ในบริบทเหล่านั้นได้

EXECUTEประการที่สองคุณยังสามารถเป็น Scalar UDF ไวยากรณ์นี้มีประโยชน์มากเมื่อคุณมีค่าเริ่มต้นที่ระบุไว้สำหรับพารามิเตอร์อินพุต ใช้ UDF ต่อไปนี้ตัวอย่างเช่น:

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

หากคุณต้องการใช้พารามิเตอร์อินพุตใด ๆ เป็น "ทางเลือก" คุณยังคงต้องผ่านDEFAULTคำหลักเมื่อเรียกมันว่าเป็นฟังก์ชั่นเนื่องจากมีการแก้ไขลายเซ็น:

DECLARE @Bob1 INT;

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

SELECT @Bob1;
-- Returns: 102

ในทางกลับกันถ้าคุณEXECUTEใช้ฟังก์ชั่นคุณสามารถใช้พารามิเตอร์ใด ๆ ที่มีค่าเริ่มต้นเป็นตัวเลือกอย่างแท้จริงเช่นเดียวกับที่คุณทำได้ด้วย Stored Procedure คุณสามารถส่งผ่านในครั้งแรกnพารามิเตอร์โดยไม่ต้องระบุชื่อพารามิเตอร์:

DECLARE @Bob2 INT;

EXEC @Bob2 = dbo.OptionalParameterTest 50;

SELECT @Bob2;
-- Returns: 52

คุณสามารถข้ามพารามิเตอร์แรกได้โดยระบุชื่อพารามิเตอร์อีกครั้งเช่นเดียวกับ Stored Procedure:

DECLARE @Bob3 INT;

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

SELECT @Bob3;
-- Returns: 51

UPDATE

ทำไมคุณอาจต้องการใช้EXECไวยากรณ์เพื่อเรียกใช้ scalar UDF เช่นเดียวกับ Stored Procedure ในบางครั้งมี UDF ที่ยอดเยี่ยมที่จะมีเป็น UDF เนื่องจากสามารถเพิ่มลงในคิวรีและดำเนินการกับชุดของแถวที่ส่งคืนได้ในขณะที่ถ้ารหัสอยู่ในกระบวนงานที่เก็บไว้มันจะต้องถูกวางลงในเคอร์เซอร์เพื่อ วนซ้ำแถวหนึ่งชุด แต่มีบางครั้งที่คุณต้องการเรียกใช้ฟังก์ชันนั้นในค่าเดียวซึ่งอาจมาจากภายใน UDF อื่น การเรียกใช้ UDF สำหรับค่าเดียวสามารถทำได้ดังนี้:

SELECT dbo.UDF('some value');

ในกรณีนี้คุณจะได้รับค่าตอบแทนในชุดผลลัพธ์ (ชุดผลลัพธ์จะไม่ทำงาน) หรือสามารถทำได้ดังนี้

DECLARE @Dummy INT;

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

ในกรณีนี้คุณต้องประกาศ@Dummyตัวแปร

อย่างไรก็ตามด้วยEXECไวยากรณ์คุณสามารถหลีกเลี่ยงสิ่งรบกวนทั้งสองได้:

EXEC dbo.UDF 'some value';

นอกจากนี้ UDF สเกลาร์ยังมีแผนการดำเนินการที่แคชไว้ ซึ่งหมายความว่าเป็นไปได้ที่จะพบปัญหาการดมกลิ่นของพารามิเตอร์หากมีเคียวรีใน UDF ที่มีแผนการดำเนินการ สำหรับสถานการณ์ที่เป็นไปได้ที่จะใช้EXECไวยากรณ์ดังนั้นจึงเป็นไปได้ที่จะใช้WITH RECOMPILEตัวเลือกเพื่อละเว้นค่าที่รวบรวมไว้ของแผนสำหรับการดำเนินการนั้น ตัวอย่างเช่น:

ติดตั้ง:

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

ทดสอบ:

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;

4

ฉันคิดว่าความแตกต่างของสิทธิ์เป็นเพราะคุณสามารถเรียกใช้ฟังก์ชั่นที่ผู้ใช้กำหนดด้วยค่าสเกลาร์กับ EXEC เช่นเดียวกับขั้นตอนการจัดเก็บ (ซึ่งฉันไม่ได้รู้จนกระทั่งฉันขุดลงใน SQL Server 2000 Books Online ที่พวกเขาแนะนำฟังก์ชั่นที่ผู้ใช้กำหนด) แต่คุณไม่สามารถเลือกจากสิ่งเหล่านั้นเป็นแหล่งตารางได้ ตัวอย่างเช่น:

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

ในกรณีนี้ dbo.first_day_of_month เป็นฟังก์ชันที่ผู้ใช้กำหนด ฉันไม่รู้ว่าทำไมคุณถึงเรียกใช้ฟังก์ชันด้วยวิธีนี้ แต่ฉันจะคาดเดาว่าพวกเขาต้องการสิทธิ์ EXECUTE แทนที่จะใช้ SELECT เพื่อรักษาความมั่นคง ทุกวันนี้มันอาจจะเป็นเพียงสัมภาระที่เข้ากันได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.