2010-02-25 37 views
6

Tôi biết nó có vẻ giống như một điều cơ bản, nhưng tôi chưa bao giờ làm điều này trước đây.Cách trả về bản ghi từ một bảng hiện có từ một hàm Oracle PL/SQL?

Tôi muốn trả lại một bản ghi từ một bảng hiện có dưới dạng kết quả của một hàm Oracle PL/SQL. Tôi đã tìm thấy một số cách khác nhau để thực hiện việc này, nhưng tôi quan tâm đến cách tốt nhất để thực hiện điều này (đọc: Tôi không hài lòng với những gì tôi đã tìm thấy).

Nắm bắt những gì tôi đang làm là ... Tôi có một bảng gọi là 'người dùng' và tôi muốn một hàm 'update_and_get_user' được cung cấp Tên người dùng (cũng như thông tin đáng tin cậy khác về người dùng đã nói) thực hiện các hành động khác nhau trên bảng 'người dùng', và sau đó trả về số không hoặc một hàng/bản ghi từ bảng đã nói.

Đây là phác thảo cơ bản của mã trong đầu tôi lúc này (đọc: không có ý tưởng nếu cú ​​pháp thậm chí còn gần đúng):

CREATE FUNCTION update_and_get_user(UserName in VARCHAR2, OtherStuff in VARCHAR2) 
    RETURN users PIPELINED IS 
    TYPE ref0 IS REF CURSOR; 
    cur0  ref0; 
    output_rec users%ROWTYPE; 
BEGIN 
    -- Do stuff 

    -- Return the row (or nothing) 
    OPEN cur0 FOR 'SELECT * FROM users WHERE username = :1' 
    USING UserName; 

    LOOP 
    FETCH cur0 INTO output_rec; 
    EXIT WHEN cur0%NOTFOUND; 
    PIPE ROW(output_rec); 
    END LOOP; 
END update_and_get_user; 

Tôi đã nhìn thấy những ví dụ nơi một kỷ lục hoặc bàn là trả về, kiểu bản ghi hoặc bảng đã được tạo/khai báo trước, nhưng có vẻ như nếu bảng đã được định nghĩa, tôi có thể sử dụng nó, và do đó không phải lo lắng về việc đồng bộ mã khai báo kiểu nếu bảng thay đổi đã từng được thực hiện.

Tôi mở cho tất cả các giải pháp và bình luận tiềm năng, nhưng tôi thực hiện thực sự muốn giữ điều này trong một hàm PL/SQL đơn lẻ (trái ngược với mã trong một số ngôn ngữ/khuôn khổ khác liên lạc với cơ sở dữ liệu nhiều lần , kết thúc bằng một số dạng 'SELECT * FROM users WHERE username = blah') khi hệ thống gọi hàm và bản thân cơ sở dữ liệu có thể là các thành phố khác nhau. Bên ngoài giới hạn đó, tôi cởi mở để thay đổi suy nghĩ của mình.

Trả lời

12

Đây là cách tôi sẽ làm. Các biến/tên bảng/tên cột có phân biệt chữ hoa chữ thường trong Oracle, vì vậy tôi sẽ sử dụng user_name thay vì UserName.

CREATE TABLE users(UserName varchar2(20), OtherStuff VARCHAR2(20)); 

Chức năng update_and_get_user. Lưu ý rằng tôi trả lại ROWTYPE thay vì Bảng được nối ống.

CREATE OR REPLACE FUNCTION update_and_get_user(
    in_UserName IN users.UserName%TYPE, 
    in_OtherStuff IN users.OtherStuff%TYPE) 
RETURN users%ROWTYPE 
IS 
    output_rec users%ROWTYPE; 
BEGIN 
    UPDATE users 
    SET OtherStuff = in_OtherStuff 
    WHERE UserName = in_UserName 
    RETURNING UserName, OtherStuff 
    INTO output_rec; 
    RETURN output_rec; 
END update_and_get_user; 

Và đây là cách bạn sẽ gọi. Bạn không thể kiểm tra số ROWTYPE thành NULL, nhưng bạn có thể kiểm tra username chẳng hạn.

DECLARE 
    users_rec users%ROWTYPE; 
BEGIN 
    users_rec := update_and_get_user('user', 'stuff'); 
    IF(users_rec.username IS NOT NULL) THEN 
    dbms_output.put_line('FOUND: ' || users_rec.otherstuff); 
    END IF; 
END; 

Một giải pháp sử dụng PIPED ROWS là dưới đây, nhưng nó không hoạt động theo cách đó. Bạn không thể cập nhật các bảng bên trong một truy vấn.

SELECT * FROM TABLE(update_and_get_user('user', 'stuff')) 

ORA-14551: cannot perform a DML operation inside a query 

Solution sẽ trông như thế:

CREATE OR REPLACE TYPE users_type 
AS OBJECT 
(
    username VARCHAR2(20), 
    otherstuff VARCHAR2(20) 
) 

CREATE OR REPLACE TYPE users_tab 
    AS TABLE OF users_type; 

CREATE OR REPLACE FUNCTION update_and_get_user(
    in_UserName IN users.username%TYPE, 
    in_OtherStuff IN users.otherstuff%TYPE) 
RETURN users_tab PIPELINED 
IS 
    output_rec users%ROWTYPE; 
BEGIN 
    UPDATE users 
    SET OtherStuff = in_OtherStuff 
    WHERE UserName = in_UserName 
    RETURNING username, otherstuff 
    INTO output_rec; 
    PIPE ROW(users_type(output_rec.username, output_rec.otherstuff)); 
END; 
+0

+1 toàn diện câu trả lời Peter - bạn đánh bại tôi vào nó (cần phải tăng tốc độ đánh máy của tôi) Trong trường hợp cần thiết Paul, liên kết này (http : //download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/rowtype_attribute.htm#LNPLS01342) giải thích thuộc tính% rowtype –

+1

+1 Peter! Tôi ước tôi có thể đưa ra nhiều phiếu bầu. Đầu tiên, điều này có vẻ thực sự tốt. Thứ hai, tôi không biết bạn có thể làm "RETURNING ... INTO ..." trong một CẬP NHẬT, điều đó thực sự tuyệt vời và sẽ tăng hiệu suất.Thứ ba, tôi không biết ai không thể thực hiện cập nhật bên trong một truy vấn của một hàm bảng, mà cuối cùng sẽ làm tôi thất vọng. Tôi sẽ đánh dấu câu trả lời này là câu trả lời được chấp nhận khi tôi thực hiện việc này/xác minh nó. Cảm ơn bạn! –

+0

Vâng, chúc may mắn sau đó :) –

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