2010-10-19 23 views
5

Tôi đang tìm cách tối ưu để tạo một hàm có thể chấp nhận không có tham số và trả về tất cả kết quả, nhưng cũng chấp nhận tham số và trả lại kết quả đó.ORACLE PL/SQL: Chức năng và tham số tùy chọn, như thế nào?

Chuẩn Tôi đã đối phó với tại công việc của tôi là thế này:

FUNCTION get_records (
    i_code         IN records.code%type := NULL, 
    i_type         IN records.type%type := NULL 
) RETURN results 

Vấn đề là tôi muốn trả lại hồ sơ đó có một loại NULL là tốt, và sử dụng:

WHERE type = nvl(i_type, type) 

Nó chỉ trả về các bản ghi với các loại thực tế chứ không phải các bản ghi rỗng .. vì các lý do rõ ràng. Tôi đã chỉ tự hỏi nếu có một cách tiêu chuẩn để làm điều này có thể được thực hiện trên tất cả các chức năng chúng tôi sử dụng. Thật trùng hợp, nếu tôi cung cấp một tham số ... Tôi không muốn các giá trị NULL của trường đó.

Trả lời

5

tại sao không chỉ đơn giản là những gì bạn có với việc bổ sung

type = i_type OR (i_type IS NULL AND type IS NULL) 

theo cách đó, khi được thông qua vào param là null nó sẽ tìm kiếm tất cả mọi thứ (bao gồm null) hoặc giá trị quy định. Bây giờ, nếu bạn chỉ muốn nulls ...

dụ (thay đổi giá trị null đến 5 và bạn sẽ thấy đầu ra)

WITH TESTDATA AS (
     SELECT LEVEL dataId 
      FROM DUAL 
     CONNECT BY LEVEL <= 100 
     UNION 
     SELECT NULL 
     from dual 
) 
SELECT * 
    FROM TESTDATA 
where dataId = :n or (:n is null AND dataId is null) ; 

Trong đó: n = 6 kết quả sẽ

DATAID     
---------------------- 
6 

(xóa a new post, đọc sai một param) Nhưng tôi thích cách tiếp cận mới và tránh NVL

đây là một cách tiện lợi để làm điều đó nếu bạn không phải là bất lợi to SQL động

http://www.oracle.com/technetwork/issue-archive/2009/09-jul/o49asktom-090487.html

+0

Đây thực sự là những gì tôi đã triển khai sau khi thử nghiệm ... – jlrolin

+3

Tôi khuyên bạn nên thay đổi nó thành 'type = i_type OR i_type IS NULL'. Đây là kinh nghiệm của tôi nhiều khả năng tận dụng lợi thế của một chỉ mục trên 'loại' hơn là sử dụng NVL(). Ngoài ra, có vẻ rõ ràng hơn với tôi. –

+0

@Dave: Đó là giải pháp tôi đã triển khai. – jlrolin

3

Ngay trên đỉnh đầu của tôi, tôi đoán việc sử dụng từ khóa DEFAULT sẽ thực hiện thủ thuật, phải không? (Liên kết sau sẽ cung cấp thêm một số chi tiết.)

  1. Using the DEFAULT keyword.

    CREATE OR REPLACE FUNCTION get_records (
        i_code IN records.code%type DEFAULT NULL, 
        i_type IN records.type%type DEFAULT NULL 
    ) RETURN results 
    

EDIT # 1

Nếu tôi hiểu câu hỏi một cách chính xác, bạn muốn trả lại tất cả các hồ sơ khi tham số i_type là NULL. Nếu không có thêm chi tiết, tôi đoán là như sau.

CREATE OR REPLACE FUNCTION get_records (
    i_code IN records.code%TYPE DEFAULT NULL, 
    i_type IN records.type%TYPE DEFAULT NULL 
) RETURN results 
BEGIN 
    IF (i_type IS NULL) THEN 
     select * 
      from table 
    ELSE 
     select * 
      from table 
      where type = NVL(i_type, type) 
    END IF 

    EXCEPTION 
     WHEN OTHERS THEN 
      NULL 
END 

Đó là tất cả những gì tôi có thể làm với thông tin được cung cấp, mặc dù nội dung chức năng được nhận xét bên dưới.

EDIT # 2

Tôi là một chút gỉ từ Oracle, vì vậy tôi tham khảo ý kiến ​​một số tài liệu như liên kết dưới đây:

Oracle/PLSQL: NVL Function

Như tôi đã đọc nó, bạn đã tốt hơn sử dụng NVL chức năng trong hướng dẫn SELECT của bạn chứ không phải mệnh đề WHERE của bạn.

Cuối cùng, câu hỏi của bạn chính xác là gì? Bạn có thể làm cho nó tinh thể rõ ràng?

+1

Dấu ': = 'trong khai báo tham số giống với' DEFAULT'. Vấn đề dường như là một giá trị NULL cho tham số có nghĩa là khớp các bản ghi với một giá trị NULL trong cột tương ứng; Vậy giá trị mặc định sẽ được sử dụng để chỉ ra "tất cả các bản ghi" là gì? –

+0

Không trả lại các bản ghi có loại NULL. Về cơ bản tôi muốn bằng loại nếu tôi cung cấp tham số, nếu không thì không sử dụng tham số. Đây không phải là SQL động, vì vậy bạn có thể thấy tình huống khó xử. Nếu có, tôi sẽ loại trừ mệnh đề. – jlrolin

+0

@Dave Costa: Cảm ơn thông tin. Tôi đã luôn luôn và chỉ sử dụng từ khóa 'DEFAULT', và không phải là dấu bằng (': = ') để xác định các giá trị mặc định. –

3

Để nhắc lại vấn đề của mình: Bạn không thể lấy giá trị mặc định là NULL để có nghĩa là "trả lại tất cả hồ sơ", vì hành vi dự kiến ​​hiện tại là nó sẽ chỉ trả lại những bản ghi đó giá trị thực sự là NULL.

Một khả năng là thêm tham số boolean tương ứng với mỗi thông số tra cứu, cho biết liệu tham số này có thực sự được sử dụng để lọc kết quả hay không. Một vấn đề tiềm năng với điều này là người gọi có thể chỉ định giá trị tra cứu nhưng không đặt cờ thành đúng, tạo ra kết quả không mong muốn. Bạn có thể bảo vệ chống lại điều này trong thời gian chạy bằng cách tăng ngoại lệ nếu cờ là sai cho bất kỳ giá trị tra cứu nào khác ngoài NULL.

Một khả năng khác là xác định giá trị ngoài miền cho mỗi cột tra cứu - ví dụ: nếu chuỗi 'BẤT K' 'được chuyển cho tham số, chuỗi đó sẽ không lọc các giá trị trên cột đó. Điều này sẽ làm việc tốt miễn là bạn có thể tìm thấy một giá trị sentry đáng giá cho mỗi cột. Tôi muốn đề nghị tuyên bố các giá trị sentry như hằng số trong một số gói, để các cuộc gọi đến chức năng có thể trông giống như get_records(PKG.ALL_CODES, 'type1').

4

Cách thông thường để giải quyết vấn đề này là quá tải chức năng, thay vì sử dụng các giá trị mặc định:

FUNCTION get_records (
    i_code         IN records.code%type, 
    i_type         IN records.type%type 
) RETURN results; 

FUNCTION get_records (
    i_code         IN records.code%type 
) RETURN results; 

FUNCTION get_records RETURN results; 

Lưu ý: Nếu bạn cũng cần một phiên bản i_type của chính nó, bạn có thể gặp rắc rối nếu nó có cùng loại cơ bản là i_code - trong trường hợp đó, bạn cần sử dụng một tên khác cho hàm đó.

+0

+1: Điều đó, hoặc sử dụng SQL động –

+0

@OMG: tốt, giải pháp của tôi không nói gì về việc SQL động có được sử dụng hay không - vấn đề là làm thế nào để bạn biết giữa get_records (NULL, NULL) và get_records (NULL), trừ khi bạn tạo nên một số "giá trị ma thuật" cho các tham số mặc định? Quá tải là cách tốt nhất để giải quyết vấn đề này, IMO. –

1

tôi đã được sử dụng hack như sau (giả sử p_product là một đầu vào thủ tục bắt buộc):

nơi t.product = decode (p_product, null, t.product, p_product)

procedure get_data(p_product in number := null) 
... 
select * 
from tbl t 
where t.product = decode(p_product, null, t.product, p_product); 
... 

Điều này sẽ tạo ra trường hợp 'ở đâu 1 = 1' khi sản phẩm không được chuyển vào và sử dụng sản phẩm nếu không. Một nhược điểm lớn có thể xảy ra là điều này phân tích cú pháp đến cùng một kế hoạch thực hiện bất kể tham số.

Các vấn đề liên quan