Có cách nào đơn giản trong PL / pgSQL để kiểm tra xem một truy vấn không có kết quả không?


16

Tôi hiện đang thử nghiệm một chút với PL / pgSQL và muốn biết liệu có cách nào thanh lịch hơn để làm điều gì đó như thế này không:

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;

Câu trả lời:


21

Các khối ngoại lệ có nghĩa là cho các lỗi bẫy, không kiểm tra các điều kiện. Nói cách khác, nếu một số điều kiện có thể được xử lý tại thời điểm biên dịch, thì nó không nên bị mắc kẹt như lỗi mà được giải quyết bằng logic chương trình thông thường.

Trong phần Bẫy lỗi của tài liệu PL / PGQuery, bạn có thể tìm thấy mẹo như sau:

Mẹo: Một khối chứa mệnh đề EXCEPTION đắt hơn đáng kể để nhập và thoát so với khối không có. Do đó, không sử dụng NGOẠI TRỪ mà không cần.

Thay vì sử dụng các ngoại lệ (xấu) hoặc IF / THEN / ELSIF (tốt hơn), bạn có thể viết lại thành một truy vấn:

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;

Nếu bạn thực sự muốn hai truy vấn, bạn có thể sử dụng biến FOUND đặc biệt để kiểm tra xem truy vấn trước đó có cho kết quả nào không:

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;

Liên kết RTFM bắt buộc folllow :-)

Xem phần này để mô tả FOUNDbiến và cái này cho IF/ THENkhối.


13

Bạn có thể kiểm tra một biến đặc biệt FOUND của một kiểu boolean. Từ tài liệu:

FOUND bắt đầu sai trong mỗi lệnh gọi hàm PL / pgSQL. Nó được thiết lập bởi mỗi loại câu lệnh sau:

Câu lệnh CHỌN VÀO đặt FOUND đúng nếu một hàng được gán, sai nếu không có hàng nào được trả về.

Câu lệnh PERFORM đặt FOUND true nếu nó tạo (và loại bỏ) một hoặc nhiều hàng, sai nếu không có hàng nào được tạo.

Các câu lệnh CẬP NHẬT, CHERTN và XÓA đặt FOUND true nếu ít nhất một hàng bị ảnh hưởng, sai nếu không có hàng nào bị ảnh hưởng.

Câu lệnh FETCH đặt FOUND true nếu nó trả về một hàng, false nếu không có hàng nào được trả về.

Câu lệnh MOVE đặt FOUND true nếu nó định vị lại thành công con trỏ, ngược lại là sai.

Câu lệnh FOR hoặc FOREACH đặt FOUND true nếu nó lặp lại một hoặc nhiều lần, nếu không thì sai. FOUND được đặt theo cách này khi vòng lặp thoát; bên trong việc thực hiện vòng lặp, FOUND không được sửa đổi bởi câu lệnh vòng lặp, mặc dù nó có thể được thay đổi bằng cách thực hiện các câu lệnh khác trong thân vòng lặp.

Các câu lệnh TRẢ LẠI QUAY LẠI và QUAY LẠI QUAY QUẢNG CÁO đặt FOUND đúng nếu truy vấn trả về ít nhất một hàng, sai nếu không có hàng nào được trả về.

Các câu lệnh PL / pgSQL khác không thay đổi trạng thái FOUND. Đặc biệt lưu ý rằng EXECUTE thay đổi đầu ra của GET DIAGNOSTICS, nhưng không thay đổi FOUND.

FOUND là một biến cục bộ trong mỗi hàm PL / pgSQL; mọi thay đổi đối với nó chỉ ảnh hưởng đến chức năng hiện tại.


nhưng select intotrả về không có dữ liệu vẫn sẽ đưa ra một ngoại lệ, phải không?
Jack Douglas

3
nói chung là không, nó chỉ tăng ngoại lệ nếu mệnh đề STRICT được chỉ định, như CHỌN * VÀO
CHIẾN LƯỢC

à vâng, cái xấu của tôi - mặc dù điều đó không có nghĩa là bộ xử lý ngoại lệ trong ví dụ OP sẽ không bao giờ kích hoạt? :-)
Jack Douglas

1
@JackDoumund: Nói chung, không có dữ liệu nào không phải là nguyên nhân của ngoại lệ (ngoại trừ các trường hợp đặc biệt như công cụ sửa đổi STRICT ở trên). OP đã có một quan niệm sai lầm ở đó.
Erwin Brandstetter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.