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;

请帮忙

4

4 回答 4

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

于 2010-07-16T14:02:41.327 回答
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;

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

于 2010-07-16T13:33:02.550 回答
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);
于 2010-07-16T06:33:48.600 回答
0

也许这可以帮助你做你想做的事?

http://it.toolbox.com/blogs/database-solutions/returning-rows-through-a-table-function-in-oracle-7802

于 2010-07-16T06:39:27.650 回答