T-SQL - ฟังก์ชันพร้อมพารามิเตอร์เริ่มต้น


155

ฉันมีสคริปต์นี้:

CREATE FUNCTION dbo.CheckIfSFExists(@param1 INT, @param2 BIT = 1 )
RETURNS BIT
AS
BEGIN
    IF EXISTS ( bla bla bla )
        RETURN 1;
    RETURN 0;
END
GO

ฉันต้องการใช้ในขั้นตอนด้วยวิธีนี้:

IF dbo.CheckIfSFExists( 23 ) = 0
    SET @retValue = 'bla bla bla';

แต่ฉันได้รับข้อผิดพลาด:

มีการระบุจำนวนอาร์กิวเมนต์ไม่เพียงพอสำหรับโพรซีเดอร์หรือฟังก์ชัน dbo.CheckIfSFExists

ทำไมมันไม่ทำงาน

คำตอบ:


227

คุณต้องโทรมันแบบนี้

SELECT dbo.CheckIfSFExists(23, default)

จากTechnet :

เมื่อพารามิเตอร์ของฟังก์ชันมีค่าเริ่มต้นจะต้องระบุ DEFAULT คีย์เวิร์ดเมื่อเรียกใช้ฟังก์ชันเพื่อเรียกใช้ค่าเริ่มต้น ลักษณะการทำงานนี้จะแตกต่างจากการใช้พารามิเตอร์ที่มีค่าเริ่มต้นในขั้นตอนการจัดเก็บซึ่งการละเว้นพารามิเตอร์ยังหมายถึงค่าเริ่มต้น ข้อยกเว้นสำหรับพฤติกรรมนี้คือเมื่อเรียกใช้ฟังก์ชันสเกลาร์โดยใช้คำสั่ง EXECUTE เมื่อใช้ EXECUTE คีย์เวิร์ด DEFAULT ไม่จำเป็น


80
เมื่อเห็นอย่างนี้ฉันก็หงุดหงิด ฉันไม่ได้รับประโยชน์จากdefaultแนวคิดที่นี่ ... ฉันต้องไปและเปลี่ยนสถานที่ทั้งหมดในขณะนี้
LCJ

8
@Lijo คุณยังคงได้รับประโยชน์จากการไม่ทำซ้ำค่าเริ่มต้นที่เป็นรูปธรรมในการโทรแต่ละครั้ง
Frédéric

9
เนื่องจากเราไม่ได้รับอนุญาตให้วางซ้อนและ "ค่าเริ่มต้น" จึงมีการใช้งานที่ จำกัด บ่อยครั้งวิธีที่ดีที่สุดคือสร้างรุ่นต่อเติมใหม่ด้วยคำต่อท้าย (พูดว่า CheckIfSFExistsEX ที่นี่) ด้วยพารามิเตอร์เพิ่มเติมและเปลี่ยนฟังก์ชันดั้งเดิมเป็นเพียง การเรียกใช้เวอร์ชันเพิ่มเติมด้วยพารามิเตอร์ "default" วิธีนี้ใช้งานได้กับรหัสที่มีอยู่ทั้งหมดและคุณมีเพียงที่เดียวที่จะรักษา
Eske Rahn

39

คุณสามารถเรียกมันได้สามวิธี - ด้วยพารามิเตอร์พร้อมด้วย DEFAULT และผ่าน EXECUTE

SET NOCOUNT ON;

DECLARE
@Table  SYSNAME = 'YourTable',
@Schema SYSNAME = 'dbo',
@Rows   INT;

SELECT dbo.TableRowCount( @Table, @Schema )

SELECT dbo.TableRowCount( @Table, DEFAULT )

EXECUTE @Rows = dbo.TableRowCount @Table

SELECT @Rows

11
เหตุใดจึงDEFAULTต้องเลือกคำหลัก แต่สามารถละเว้นได้ในการดำเนินการ สิ่งนี้แย่: / หวังว่าจะได้รับการแก้ไขในสักวันหนึ่ง
Misiu

@Misiu ไม่ใช่สิ่งที่ต้อง "แก้ไข" นั่นคือจากการออกแบบ ฉันอ่านทางเลือกมากมายเพื่อเข้าใกล้เป้าหมาย "อุดมคติ" เพียงแค่เรียกใช้ฟังก์ชันโดยไม่ระบุอาร์กิวเมนต์ทุกตัว แต่ฉันไม่เห็นคำอธิบายที่ชัดเจนว่าทำไมจึงต้องมี รหัสควรมีความชัดเจนและเป็นหนึ่งในกลยุทธ์ที่จะทำให้บรรลุผลซึ่งกำหนดให้ coder รู้อยู่เสมอว่า "เฮ้คุณกำลังเรียกฟังก์ชั่นที่มีและข้อโต้แย้งอื่น ๆ ที่เกิดขึ้นมีค่าเริ่มต้นอย่าลืมว่า อาจมีการเปลี่ยนแปลงค่าเริ่มต้น " IMO นี่เป็น "สิ่งเลวร้าย" ที่ควรมี
Gustavo Pinsard

16

ด้วยฟังก์ชั่นที่ผู้ใช้กำหนดคุณต้องประกาศทุกพารามิเตอร์แม้ว่าจะมีค่าเริ่มต้นก็ตาม

ต่อไปนี้จะทำงานได้สำเร็จ:

IF dbo.CheckIfSFExists( 23, default ) = 0
    SET @retValue = 'bla bla bla;

-1

วิธีหนึ่งในการแก้ไขปัญหานี้คือการใช้กระบวนงานที่เก็บไว้กับพารามิเตอร์ขาออก

exec sp_mysprocname @ ผลลัพธ์เอาท์พุทมูลค่า, @firstparam = 1, @ secondparam = 2

ค่าที่คุณไม่ส่งผ่านไปยังค่าเริ่มต้นที่ตั้งไว้ในขั้นตอนการจัดเก็บเอง และคุณสามารถรับผลลัพธ์จากตัวแปรเอาต์พุตของคุณ


1
การเปลี่ยนฟังก์ชั่นของคุณเป็นโพรซีเดอร์ที่เก็บนั้นโดยทั่วไปไม่ใช่วิธีแก้ปัญหาที่ดีเพราะไม่สามารถเรียกโพรซีเดอร์ที่เก็บไว้จากภายในเคียวรีได้ แต่ฟังก์ชั่นสามารถทำได้
Blade

จริง แต่ไม่จำเป็นต้องเรียกใช้บล็อกทั้งหมดจากภายในแบบสอบถาม มันได้รับการแสดงให้เห็นว่า sql ไม่มีวิธีการที่ดีในการจัดการค่าเริ่มต้นสำหรับฟังก์ชั่น (การใช้คำหลักเริ่มต้นเกือบจะทำงานได้ดีเท่ากับการเพิ่มค่า) มันไม่ใช่วิธีทั่วไปที่ดี แต่มันใช้งานได้ดีในบางกรณี
Jereme Guenther

ผู้คนกำลังทำเครื่องหมายสิ่งนี้อยู่เรื่อย ๆ แต่ฉันก็ยังติดอยู่ หากคุณมีความต้องการที่จะมีโค้ดที่นำมาใช้ซ้ำได้ซึ่งจะไม่ถูกเรียกใช้ภายในเคียวรีและคุณต้องการความยืดหยุ่นของพารามิเตอร์ทางเลือกจริงที่มีค่าเริ่มต้นขั้นตอนการจัดเก็บยังดีกว่าฟังก์ชั่น
Jereme Guenther

1
การใช้โพรซีเดอร์ที่เก็บไว้ไม่ได้หมายถึงการใช้มันแทนที่จะใช้ฟังก์ชั่น - มันอาจหมายถึงการใช้โพรซีเดอร์ที่เก็บไว้เป็น wrapper รอบฟังก์ชัน ฉันใช้เทคนิคนี้บ่อยครั้ง เริ่มต้นคำหลักที่ถูกซ่อนอยู่ในขณะนี้ภายใน proc ฉันคิดว่าความคิดนี้ใช้ได้ นอกจากนี้ยังช่วยให้ฉันเริ่มต้นที่ซับซ้อนมากขึ้นถ้าฉันต้องการ - แยกออกจากฟังก์ชั่นซึ่งสามารถอยู่ในสถานะที่บริสุทธิ์มากขึ้น
J Bryan Price
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.