วิธีหยุดการประมวลผลสคริปต์ SQL


16

ฉันกำลังทำงานกับสคริปต์ sql และฉันต้องการหยุดสคริปต์ต่อไปหากเงื่อนไขบางอย่างไม่เป็นที่พอใจ

เมื่อฉันเป็น Google ฉันพบว่า RaisError ที่มีระดับความรุนแรง 20 ระดับจะยุติการใช้งาน แต่ด้วยเหตุผลบางอย่างฉันไม่สามารถใช้ตัวเลือกนั้น

โปรดบอกฉันว่ามีทางเลือกอะไรบ้างที่จะหยุดการประมวลผลสคริปต์ SQL


1
ทำไมการเพิ่มข้อผิดพลาดที่ยอมรับไม่ได้? สคริปต์นี้เป็นขั้นตอนการจัดเก็บด้วยหรือไม่
Namphibian

ฉันไม่เข้าใจคำถามของคุณอย่างชัดเจน สำหรับคำถามที่สอง ไม่ใช่นี่ไม่ใช่ SP
นักพัฒนาใหม่

1
สคริปต์คืออะไร? มันประกอบด้วยหลายแบตช์หรือไม่? คุณเห็นคำตอบที่นี่หรือไม่
Martin Smith

คำตอบ:


8

จากเอกสาร RAISERROR (การเน้นของฉัน):

ผู้ใช้สามารถระบุระดับความรุนแรงตั้งแต่ 0 ถึง 18 ระดับความรุนแรงตั้งแต่ 19 ถึง 25 สามารถระบุได้โดยสมาชิกของบทบาทเซิร์ฟเวอร์ถาวร sysadmin หรือผู้ใช้ที่มีสิทธิ์ ALTER TRACE สำหรับระดับความรุนแรงตั้งแต่ 19 ถึง 25 ต้องใช้ตัวเลือก WITH LOG

เป็นไปได้สูงว่าตัวการที่คุณรันสคริปต์นั้นไม่เป็นไปตามเกณฑ์เหล่านี้

ไม่มีอะไรผิดปกติกับการใช้RAISERROR; คุณแค่ใช้ระดับความรุนแรงที่มากเกินไป ฉันใช้ระดับ 16 เป็นค่าเริ่มต้นสำหรับข้อผิดพลาดที่ยกขึ้นและลำดับจะถูกยกเลิก หากคุณต้องการความแม่นยำมากขึ้นคุณสามารถทำตามระดับที่ Microsoft กำหนดเอง:

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้การพูดทั้งหมดนั้นขึ้นอยู่กับบริบทของสคริปต์การใช้RAISERRORอาจไม่เพียงพอเนื่องจากไม่ได้ "ออก" สคริปต์ด้วยตัวเอง (ใช้ระดับความรุนแรงปกติ)

ตัวอย่างเช่น:

RAISERROR(N'Test', 16, 1);

SELECT 1;   /* Executed! */

นี้จะทั้งยกระดับข้อผิดพลาดและกลับชุดผลลัพธ์

หากต้องการยุติสคริปต์ทันทีฉันชอบที่จะใช้RETURN(โดยใช้GOTO-type constructs มักจะหมดกำลังใจในแวดวงการเขียนโปรแกรมส่วนใหญ่ที่มีทางเลือกอื่น):

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */

หรือจัดการกับข้อผิดพลาดในการใช้TRY/CATCHซึ่งจะทำให้การประมวลผลข้ามไปยังCATCHบล็อกถ้าความรุนแรงเป็น 11 หรือสูงกว่า:

BEGIN TRY
    RAISERROR(N'Test', 16, 1);
    SELECT 1;   /* Not executed */
END TRY
BEGIN CATCH
    SELECT 2;   /* Executed */
END CATCH

BEGIN TRY
    RAISERROR(N'Test', 10, 1);
    SELECT 1;   /* Executed */
END TRY
BEGIN CATCH
    SELECT 2;   /* Not executed */
END CATCH

ปัญหาแยกคือถ้าสคริปต์ขยายหลายแบตช์ - RETURNจะออกจากแบทช์เท่านั้น:

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

SELECT 2;   /* Executed! */

ในการแก้ไขปัญหานี้คุณสามารถตรวจสอบได้@@ERRORที่จุดเริ่มต้นของทุกชุด:

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
    RETURN;

SELECT 2;   /* Not executed */

แก้ไข: มาร์ตินสมิ ธ ชี้ให้เห็นอย่างถูกต้องในความคิดเห็นนี้ใช้งานได้เพียง 2 ชุด ในการขยายแบตช์ 3 ชุดขึ้นไปคุณสามารถเรียงซ้อนข้อผิดพลาดที่เกิดขึ้นได้เช่นนั้น (หมายเหตุ: GOTOวิธีการนี้ไม่สามารถแก้ปัญหานี้ได้เนื่องจากต้องกำหนดฉลากเป้าหมายภายในแบตช์):

RAISERROR(N'Test', 16, 1);
RETURN;

SELECT 1;   /* Not executed */
GO

IF (@@ERROR != 0)
BEGIN
    RAISERROR(N'Error already raised. See previous errors.', 16, 1);
    RETURN;
END

SELECT 2;   /* Not executed */
GO

IF (@@ERROR != 0)
BEGIN
    RAISERROR(N'Error already raised. See previous errors.', 16, 1);
    RETURN;
END

SELECT 3;   /* Not executed */

หรืออย่างที่เขาชี้ให้เห็นคุณสามารถใช้SQLCMDวิธีนี้หากเหมาะสมกับสภาพแวดล้อมของคุณ


คำแนะนำสุดท้ายนั้นใช้ไม่ได้ ดู Pastebin ฉันชอบวิธี sqlcmd ที่นี่
Martin Smith

6

คุณสามารถใช้GOTOคำสั่งเพื่อข้ามไปได้ทุกที่ที่คุณต้องการ กล่าวอีกนัยหนึ่งคุณพบข้อผิดพลาดหรือเงื่อนไขอื่น ๆ และคุณสามารถมีป้ายกำกับที่ด้านล่างของสคริปต์ (เช่นTheEndOfTheScript:) และเพียงแค่ออกgoto TheEndOfTheScript;คำสั่ง

นี่คือตัวอย่างรวดเร็ว:

print 'here is the first statement...';

print 'here is the second statement...';

-- substitute whatever conditional flow determining factor
-- you'd like here. I have chosen a dummy statement that will
-- always return true
--
if (1 = 1)
    goto TheEndOfTheScript;

print 'here is the third statement...';

print 'here is the fourth statement...';


TheEndOfTheScript:
print 'here is the end of the script...';

ผลลัพธ์ของการดำเนินการนี้จะเป็นดังต่อไปนี้:

here is the first statement...
here is the second statement...
here is the end of the script...

อย่างที่คุณเห็นGOTOมีการข้ามการพิมพ์คำสั่งที่สามและสี่และข้ามไปทางขวาไปยังป้ายกำกับ ( TheEndOfTheScript)


7
ใช้ได้เฉพาะเมื่อมีแบตช์เดียวจะแตกทันทีที่คุณมีคำสั่ง GO
Gabriel

4

0

เห็นด้วยกับSET NOEXEC ON/OFFอย่างไรก็ตามใน Stored Procs (มีบล็อกเดียว) ฉันก็ใช้RETURNคำสั่ง

Caveats: ในไฟล์สคริปต์หากคุณมีหลายชุดGOคำสั่งRETURNจะออกมาจากบล็อกปัจจุบันเท่านั้นและดำเนินการกับบล็อก / แบทช์ถัดไป

หมายเหตุ: GOTOควรเป็นวิธีการเข้ารหัสที่ไม่ดีTRY..CATCHแนะนำให้ใช้ " " ตามที่แนะนำตั้งแต่ SQL Server 2008 ตามด้วยTHROWในปี 2012

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