I'm trying to randomly select a card from a table of cards
with columns c_value
and c_suit
using a procedure. After selecting it, the procedure should update that entry's taken
field to be 'Y'.
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;
Then I am trying to get the selected card and output what it is as a start. With this:
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;
/
However i got the error stated in the title and it seems my way of selecting a random card is stopping me from doing an update. Thanks in advance!
Here is a different take on the scenario (I did also address your immediate problem in a different answer).
Given that we really are building a card-dealing program (as opposed to working with a test case for a business scenario) I didn't like the
TAKEN
column. Updating a table column to mark a transitory state seems wrong. What happens when we want to play another game?The following solution resolves this by populating an array with all the cards in a random order upfront (the shuffle). The cards are dealt by simply taking the next entry off the stack. The package offers a choice of approach for running out of cards: either throw a user-defined exception or just cycle through the deck again.
Here it is in action. Don't use an open
LOOP
if you set the continuous dealing mode toY
.You may think I'm not dealing with a full deck. You wouldn't be the first to think that ;)