2010-07-16 17 views
1

oracle je souhaite sélectionner quelques lignes au hasard d'une table, mettez à jour une colonne dans les lignes et les retourner en utilisant la procédure stockéeoracle procédure stockée - sélectionnez, mise à jour et retourner un ensemble aléatoire de lignes

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; 

S'IL VOUS PLAÎT AIDE

Répondre

0

Je ne sais pas où vous faites votre commis, mais en fonction du code tel qu'il est tout ce que vous avez besoin de faire est ... SELECT dU POINT oU ETAT = « commencé »

Si elle est un petit nombre , vous pouvez conserver une collection de ROWID. si elle est plus grande, alors je faire une

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); 

Retournez ensuite un curseur de

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

Une solution possible:

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; 

Si le nombre de lignes est particulièrement importante, la solution temporaire globale peut être mieux.

1

Faisant suite à une excellente recommandation 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; 
/

Quelques notes:

  1. Ce n'a pas été testé.

  2. Vous devrez remplacer la section entre parenthèses dans les déclarations de type avec les types appropriés pour votre schéma.

  3. Vous devez trouver une valeur appropriée dans la clause SAMPLE de l'instruction SELECT; il pourrait être possible de passer cela en argument, mais cela peut nécessiter l'utilisation de SQL dynamique. Cependant, si votre exigence est d'obtenir des lignes aléatoires de la table - ce que le filtrage par ROWNUM ne suffit pas - vous voudrez faire quelque chose comme ça. Étant donné que vous CHOISISSEZ FOR UPDATE, une session peut en bloquer une autre. Si vous êtes en 11g, vous pouvez examiner la clause SKIP LOCKED de l'instruction SELECT, ce qui permettra à plusieurs sessions simultanées d'exécuter du code comme celui-ci.