хранимая процедура оракула - выберите, обновите и верните случайный набор строк - PullRequest
1 голос
/ 16 июля 2010

оракул, я хочу выбрать несколько строк случайным образом из таблицы, обновить столбец в этих строках и вернуть их, используя хранимую процедуру

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 ]

1 голос
/ 16 июля 2010

Выполнение превосходной рекомендации Сюула Янссена:

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. Вам нужно будет найти подходящее значение в предложении SAMPLEоператор SELECT;может быть возможно передать это в качестве аргумента, но для этого может потребоваться использование динамического SQL.Однако, если вам необходимо получить случайные строки из таблицы - чего не сможет выполнить только фильтрация по ROWNUM - вы захотите сделать что-то вроде этого.

  4. Потому что вы 'ВЫБОР ДЛЯ ОБНОВЛЕНИЯ, один сеанс может заблокировать другой.Если вы находитесь в 11g, вы можете захотеть изучить предложение SKIP LOCKED оператора SELECT, которое позволит нескольким одновременным сеансам запускать такой код.

0 голосов
/ 16 июля 2010

Может быть, это поможет вам сделать то, что вы хотите?

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

0 голосов
/ 16 июля 2010

Возможное решение:

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;

Если число строк особенно велико, глобальное временное решение может быть лучше.

0 голосов
/ 16 июля 2010

Не уверен, где вы делаете свои коммиты, но на основе существующего кода все, что вам нужно сделать, это ВЫБРАТЬ ... ИЗ ПУНКТА, ГДЕ СОСТОЯНИЕ СТАТУСА = 'начал'

Если это маленькие цифрыВы можете сохранить коллекцию 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);
...