1

オラクルテーブルからランダムにいくつかの行を選択し、それらの行の列を更新し、ストアドプロシージャを使用してそれらを返したい

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

コミットをどこで行っているかはわかりませんが、現状のコードに基づいて行う必要があるのは、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

考えられる解決策:

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

たぶん、これはあなたがやりたいことをするのに役立つでしょうか?

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

于 2010-07-16T06:39:27.650 に答える