2

cards列のあるテーブルからランダムにカードを選択し、手順c_valueを使用しようとしています。それを選択した後、プロシージャはそのエントリのフィールドを「Y」にc_suit更新する必要があります。taken

create or replace procedure j_prc_sel_card(p_value OUT number,
                                           p_suit OUT number)
AS

   CURSOR CUR_GET_RAND_CARD IS SELECT c_value, 
                                      c_suit
                                 FROM (SELECT c_value, 
                                              c_suit, 
                                              taken
                                         FROM jackson_card
                                     ORDER BY dbms_random.value)
                                WHERE rownum = 1
                        FOR UPDATE OF taken;

BEGIN

  OPEN CUR_GET_RAND_CARD;
  FETCH CUR_GET_RAND_CARD into p_value, p_suit;

  UPDATE jackson_card 
     SET taken = 'Y' 
   WHERE c_value = p_value 
     AND c_suit = p_suit;

  CLOSE CUR_GET_RAND_CARD;

END;

次に、選択したカードを取得して、それが何であるかを開始として出力しようとしています。これとともに:

SET serveroutput on;

DECLARE v_value number;
        v_suit number;

BEGIN

  j_prc_sel_card(p_value => v_value,p_suit => v_suit);
  DBMS_OUTPUT.PUT_LINE(v_value);
  DBMS_OUTPUT.PUT_LINE(v_suit);

END;
/

しかし、タイトルにエラーが記載されていて、ランダムなカードを選択する方法が更新を妨げているようです。前もって感謝します!

4

2 に答える 2

2

これはシナリオの別の見方です(私は別の答えであなたの当面の問題にも対処しました)。

TAKEN私たちが本当にカード取引プログラムを構築していることを考えると(ビジネスシナリオのテストケースで作業するのではなく)、私はこのコラムが好きではありませんでした。一時的な状態をマークするためにテーブル列を更新するのは間違っているようです。別のゲームをプレイしたい場合はどうなりますか?

次の解決策は、事前にランダムな順序ですべてのカードをアレイに投入することでこれを解決します(シャッフル)。カードは、スタックから次のエントリーを取り除くだけで配られます。このパッケージは、カードを使い果たすためのアプローチの選択肢を提供します。ユーザー定義の例外をスローするか、デッキをもう一度循環します。

create or replace package card_deck is

    no_more_cards exception;
    pragma exception_init(no_more_cards, -20000);

    procedure shuffle;

    function deal_one 
        ( p_yn_continuous in varchar2 := 'N')
        return cards%rowtype;

end card_deck;
/

create or replace package body card_deck is

    type deck_t is table of cards%rowtype;
    the_deck deck_t;

    card_counter pls_integer;

    procedure shuffle is
    begin
        dbms_random.seed (to_number(to_char(sysdate, 'sssss')));
        select *
        bulk collect into the_deck
        from cards
        order by dbms_random.value;
        card_counter := 0;
    end shuffle;

    function deal_one
        ( p_yn_continuous in varchar2 := 'N')
        return cards%rowtype
    is
    begin
        card_counter := card_counter + 1;
        if card_counter > the_deck.count() 
        then
            if p_yn_continuous = 'N'
            then
                raise no_more_cards;
            else
                card_counter := 1;
            end if;
        end if;
        return the_deck(card_counter);
    end deal_one;

end card_deck;
/

ここでそれが実行されています。LOOP連続取引モードをに設定する場合は、オープンを使用しないでくださいY

SQL> set serveroutput on
SQL>
SQL> declare
  2      my_card cards%rowtype;
  3  begin
  4      card_deck.shuffle;
  5      loop
  6          my_card := card_deck.deal_one;
  7          dbms_output.put_line ('my card is '||my_card.c_suit||my_card.c_value);
  8      end loop;
  9  exception
 10      when card_deck.no_more_cards then
 11          dbms_output.put_line('no more cards!');
 12  end;
 13  /
my card is HA
my card is H7
my card is DJ
my card is CQ
my card is D9
my card is SK
no more cards!

PL/SQL procedure successfully completed.

SQL>

あなたは私がフルデッキを扱っていないと思うかもしれません。あなたはそれを最初に考えることはないでしょう;)

于 2009-12-08T07:00:48.807 に答える
1

ROWNUM = 1すでに明示カーソルを使用しているので、フィルターは必要ありません。これを試して:

create or replace procedure j_prc_sel_card(p_value OUT number,
                                           p_suit OUT number)
AS

   CURSOR CUR_GET_RAND_CARD IS 
         SELECT c_value, 
                c_suit, 
                taken
         FROM jackson_card
         WHERE taken != 'Y'
         ORDER BY dbms_random.value
         FOR UPDATE OF taken;

BEGIN

  OPEN CUR_GET_RAND_CARD;
  FETCH CUR_GET_RAND_CARD into p_value, p_suit;

  UPDATE jackson_card 
     SET taken = 'Y' 
   WHERE CURRENT OF cur_get_rand_card;

  CLOSE CUR_GET_RAND_CARD;

END;

の使用に注意してくださいWHERE CURRENT OF。これは、を使用しているときに行を見つける最も効率的な方法ですFOR UPDATE CLAUSE。句を使用しないNOWAIT場合、選択したカードが別のセッションによってロックされていると、カーソルがハングします。ありそうもないシナリオですが、カードゲームを超えて実際のシナリオに移行する場合は検討する価値があります。

DBMS_RANDOM.SEED()また、真にランダムなシャッフルの場合は、手続きの開始時 に呼び出す必要があることを忘れないでください。

于 2009-12-08T06:19:54.223 に答える