oracle存储过程 - 选择,更新并返回一组随机行

时间:2010-07-16 05:29:38

标签: oracle ref-cursor

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;

请帮助

4 个答案:

答案 0 :(得分:1)

跟进Sjuul Janssen的出色建议:

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. 因为您正在选择FOR UPDATE,所以一个会话可以阻止另一个会话。如果你是11g,你可能希望检查SELECT语句的SKIP LOCKED子句,这将使多个并发会话能够运行这样的代码。

答案 1 :(得分:0)

不知道你在做什么提交,但根据代码,你需要做的就是SELECT ... FROM ITEM WHERE STATUS ='started'

如果是小数字,您可以保留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);

答案 2 :(得分:0)

答案 3 :(得分: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;

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