FOR UPDATE SKIP LOCKEDで発生した動作は、このブログノートで説明されています。私の理解では、FORUPDATE句はWHERE句の後に評価されます。 SKIP LOCKEDは、返されるはずの行のうち、ロックされていない行がないことを保証する追加のフィルターのようなものです。
あなたのステートメントは論理的に次のようになります:card_numbers
から最初の行を見つける ロックされていない場合は返却してください。明らかに、これはあなたが望むものではありません。
説明した動作を再現する小さなテストケースを次に示します。
SQL> CREATE TABLE t (ID PRIMARY KEY)
2 AS SELECT ROWNUM FROM dual CONNECT BY LEVEL <= 1000;
Table created
SESSION1> select id from t where rownum <= 1 for update skip locked;
ID
----------
1
SESSION2> select id from t where rownum <= 1 for update skip locked;
ID
----------
2番目の選択から行は返されません。カーソルを使用してこの問題を回避できます:
SQL> CREATE FUNCTION get_and_lock RETURN NUMBER IS
2 CURSOR c IS SELECT ID FROM t FOR UPDATE SKIP LOCKED;
3 l_id NUMBER;
4 BEGIN
5 OPEN c;
6 FETCH c INTO l_id;
7 CLOSE c;
8 RETURN l_id;
9 END;
10 /
Function created
SESSION1> variable x number;
SESSION1> exec :x := get_and_lock;
PL/SQL procedure successfully completed
x
---------
1
SESSION2> variable x number;
SESSION2> exec :x := get_and_lock;
PL/SQL procedure successfully completed
x
---------
2
カーソルを明示的にフェッチしたので、1行だけが返されます(1行だけがロックされます)。