2010-07-16 40 views
1

神谕我想从表中随机选择几行,更新这些行一列,并返回他们使用存储过程Oracle存储过程 - 选择,更新,并返回一组随机行

PROCEDURE getrows(box IN VARCHAR2, row_no IN NUMBER, work_dtls_out OUT dtls_cursor) AS 

    v_id VARCHAR2(20); 
    v_workname VARCHAR2(20); 
    v_status VARCHAR2(20); 

    v_work_dtls_cursor dtls_cursor; 

BEGIN 

    OPEN v_work_dtls_cursor FOR 
    SELECT id, workname, status 
    FROM item 
    WHERE status IS NULL 
    AND rownum <= row_no 
    FOR UPDATE; 

    LOOP 
    FETCH v_work_dtls_cursor 
    INTO v_id ,v_workname,v_status; 

    UPDATE item 
    SET status = 'started' 
    WHERE id=v_id; 

    EXIT 
    WHEN v_work_dtls_cursor % NOTFOUND; 
    END LOOP; 

    close v_work_dtls_cursor ; 

    /* I HAVE TO RETURN THE SAME ROWS WHICH I UPDATED NOW. 
    SINCE CURSOR IS LOOPED THRU, I CANT DO IT. */ 

END getrows; 

请HELP

回答

0

不知道你在哪里做你的承诺,但基于代码,因为它代表一切,你应该需要做的就是SELECT ... FROM ITEM WHERE STATUS =“开始”

如果是小数目,你可以保留一个ROWID集合。 如果是较大的,那么我会做一个

INSERT into a global temporary table SELECT id FROM item .. AND ROWNUM < n; 
UPDATE item SET status = .. WHERE id in (SELECT id FROM global_temp_table); 

然后返回

SELECT ... FROM item WHERE id in (SELECT id FROM global_temp_table); 
0

一种可能的解决方案:

create type nt_number as table of number; 

PROCEDURE getrows(box IN VARCHAR2, 
        row_no IN NUMBER, 
        work_dtls_out OUT dtls_cursor) AS  
    v_item_rows nt_number; 
    indx number;  
    cursor cur_work_dtls_cursor is 
    SELECT id 
    FROM item 
    WHERE status IS NULL 
    AND rownum <= row_no 
    FOR UPDATE;  
BEGIN  
    open cur_work_dtls_cursor; 
    fetch cur_work_dtls_cursor bulk collect into nt_number; 

    for indx in 1 .. item_rows.count loop 
    UPDATE item 
    SET status = 'started' 
    WHERE id=v_item_rows(indx); 
    END LOOP; 
    close cur_work_dtls_cursor; 

    open work_dtls_out for select id, workname, status 
     from item i, table(v_item_rows) t 
     where i.id = t.column_value; 
END getrows; 

如果行数特别大时,全局临时解决方案可能是更好的。

1

跟进Sjuul扬森的优秀建议:

create type get_rows_row_type as object 
    (id   [item.id%type], 
    workname [item.workname%type], 
    status  [item.status%type] 
) 
/

create type get_rows_tab_type as table of get_rows_row_type 
/

create function get_rows (box in varchar2, row_no in number) 
    return get_rows_tab_type pipelined 
as 
    v_work_dtls_cursor dtls_cursor; 
    l_out_rec get_rows_row_type; 

BEGIN 

    OPEN v_work_dtls_cursor FOR 
    SELECT id, workname, status 
    FROM item sample ([ROW SAMPLE PERCENTAGE]) 
    WHERE status IS NULL 
    AND rownum <= row_no 
    FOR UPDATE; 

    LOOP 
    FETCH v_work_dtls_cursor 
    INTO l_out_rec.id, l_out_rec.workname, l_outrec.status; 
    EXIT WHEN v_work_dtls_cursor%NOTFOUND; 

    UPDATE item 
     SET status = 'started' 
    WHERE id=l_out_rec.id; 
    l_out_rec.id.status := 'started'; 

    PIPE ROW (l_out_rec); 
    END LOOP; 
    close v_work_dtls_cursor ; 
END; 
/

的几个注意事项:

  1. 这是未经测试。

  2. 您需要用适当的类型替换类型声明中的括号中的部分。

  3. 您需要在SELECT语句的SAMPLE子句中找到适当的值;有可能将它作为参数传递,但这可能需要使用动态SQL。但是,如果您的要求是从表中获取随机行 - 只是通过ROWNUM进行过滤将无法完成 - 您将需要这样做。

  4. 因为您正在SELECTING FOR UPDATE,所以一个会话可能会阻止另一个会话。如果你在11g中,你可能希望检查SELECT语句的SKIP LOCKED子句,这将使多个并发会话能够像这样运行代码。