มีวิธีง่ายๆใน PL / pgSQL เพื่อตรวจสอบว่าแบบสอบถามไม่ส่งคืนผลลัพธ์หรือไม่?


16

ฉันกำลังทดลองกับ PL / pgSQL เล็กน้อยและต้องการทราบว่ามีวิธีที่สง่างามกว่านี้ในการทำสิ่งนี้หรือไม่:

select c.data into data from doc c where c.doc_id = id and c.group_cur > group_cur order by c.id desc limit 1;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        select c.data into data from doc c where c.doc_id = id and c.global_cur > global_cur order by c.id desc limit 1;
        EXCEPTION
            WHEN NO_DATA_FOUND THEN
                RETURN NULL;

คำตอบ:


21

บล็อกการยกเว้นนั้นมีไว้สำหรับดักข้อผิดพลาดไม่ใช่การตรวจสอบเงื่อนไข กล่าวอีกนัยหนึ่งถ้าเงื่อนไขบางอย่างสามารถจัดการในเวลารวบรวมมันไม่ควรถูกขังอยู่เป็นข้อผิดพลาด แต่แก้ไขได้ด้วยตรรกะของโปรแกรมธรรมดา

ในหัวข้อ Trapping Errors ของเอกสารประกอบ PL / PgSQLคุณสามารถหาคำแนะนำดังกล่าวได้:

เคล็ดลับ: บล็อกที่มีส่วนข้อยกเว้นมีราคาแพงกว่าการเข้าและออกมากกว่าบล็อกที่ไม่มีบล็อก ดังนั้นอย่าใช้ข้อยกเว้นโดยไม่จำเป็น

แทนที่จะใช้ข้อยกเว้น (ไม่ดี) หรือ IF / THEN / ELSIF (ดีกว่า) คุณสามารถเขียนสิ่งนี้ลงในเคียวรีเดียว:

SELECT c.data into data
FROM  doc c
WHERE c.doc_id = id
  and (
    c.group_cur > group_cur
    or
    c.global_cur > global_cur
  )
ORDER BY
  -- this will make group always preferred over global
  case when c.group_cur > group_cur then 1 else 2 end ASC,
  -- and this is your normal ordering
  c.id DESC
limit 1;

ถ้าคุณต้องการสองเคียวรีจริงๆคุณสามารถใช้ตัวแปร FOUND พิเศษเพื่อทดสอบว่าเคียวรี่ก่อนหน้านี้ให้ผลลัพธ์ใด ๆ

select c.data into data
from doc c
where c.doc_id = id and c.group_cur > group_cur
order by c.id desc limit 1;
if not found then
    select c.data into data
    from doc c
    where c.doc_id = id and c.global_cur > global_cur
    order by c.id desc limit 1;
    if not found then return null; end if;
end if;

ภาระหน้าที่ลิงก์ RTFM folllow :-)

ดูที่นี่เพื่อดูคำอธิบายของFOUNDตัวแปรและสิ่งนี้สำหรับIF/ THENบล็อก


13

คุณสามารถตรวจสอบตัวแปรพิเศษ FOUND ของบูลีนชนิด จากเอกสารประกอบ:

FOUND เริ่มต้นเป็นเท็จภายในการเรียกใช้ฟังก์ชัน PL / pgSQL แต่ละครั้ง มันถูกกำหนดโดยแต่ละประเภทของคำสั่งต่อไปนี้:

คำสั่ง SELECT ไปที่ตั้งค่า FOUND จริงถ้ามีการกำหนดแถวเป็นเท็จถ้าไม่มีการส่งคืนแถว

คำสั่ง PERFORM ตั้ง FOUND จริงถ้ามันสร้าง (และทิ้ง) หนึ่งหรือมากกว่าหนึ่งแถวเท็จถ้าไม่มีการสร้างแถว

คำสั่ง UPDATE, INSERT และ DELETE ตั้งค่า FOUND เป็นจริงหากมีอย่างน้อยหนึ่งแถวที่ได้รับผลกระทบเท็จถ้าไม่มีแถวที่ได้รับผลกระทบ

คำสั่ง FETCH ตั้งค่า FOUND จริงถ้ามันคืนแถว, เท็จถ้าไม่มีคืนแถว

คำสั่ง MOVE ตั้งค่า FOUND จริงถ้ามันสามารถเปลี่ยนตำแหน่งเคอร์เซอร์ได้สำเร็จ

คำสั่ง FOR หรือ FOREACH ตั้งค่าการพบจริงถ้ามันวนซ้ำหนึ่งครั้งหรือมากกว่านั้นเป็นเท็จ FOUND ถูกตั้งค่าแบบนี้เมื่อลูปออก ภายในการดำเนินการของลูป FOUND ไม่ได้ถูกแก้ไขโดยคำสั่งวนรอบแม้ว่ามันอาจจะมีการเปลี่ยนแปลงโดยการดำเนินการของคำสั่งอื่น ๆ ภายในร่างกายของวง

RETURN QUERY และ RETURN QUERY EXECUTE statement ตั้งค่า FOUND true หากเคียวรีคืนค่าอย่างน้อยหนึ่งแถว, false หากไม่มีการส่งคืนแถว

คำสั่ง PL / pgSQL อื่น ๆ ไม่เปลี่ยนสถานะของ FOUND โปรดสังเกตว่าโดยเฉพาะอย่างยิ่ง EXECUTE จะเปลี่ยนเอาต์พุตของ GET DIAGNOSTICS แต่จะไม่เปลี่ยน FOUND

FOUND เป็นตัวแปรท้องถิ่นภายในแต่ละฟังก์ชั่น PL / pgSQL; การเปลี่ยนแปลงใด ๆ ที่มีผลกับฟังก์ชันปัจจุบันเท่านั้น


แต่ a select intoที่ส่งคืนไม่มีข้อมูลจะยังคงยกข้อยกเว้นใช่ไหม?
แจ็คบอกว่าลอง topanswers.xyz

3
โดยทั่วไปไม่ก็ยกข้อยกเว้นเฉพาะในกรณีที่ข้อเคร่งครัดมีการระบุเช่น SELECT * INTO เคร่งครัดบันทึกของฉัน ...
alexk

อ่าใช่ฉันไม่ดี - แต่นั่นไม่ได้หมายความว่าตัวจัดการข้อยกเว้นในตัวอย่าง OP จะไม่มีไฟไหม :-)
แจ็คพูดว่าลอง topanswers.xyz

1
@JackDouglas: โดยทั่วไปไม่มีข้อมูลใด ๆ ที่เป็นสาเหตุของข้อยกเว้น (ยกเว้นในกรณีพิเศษเช่นตัวปรับ STRICT ด้านบน) OP มีความเข้าใจผิดที่นั่น
Erwin Brandstetter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.