たとえば、COBOL で、ISAM ファイルに対して、START 命令を実行すると、カレントレコードが該当のレコードに位置付きます。
あとは、データが必要になったときは、そのつど、1件ずつ READ 命令で読んでいけばよいのですが、RDB の場合、「〜より大きいキーを持つデータ」、「〜より小さいキーを持つデータ」としてしまうと、複数の行が帰ってきてしまい、レスポンスがよくありません。
このようなときは、「〜より大きいキーを持つデータのうち、最小のキーを持つデータ」、「〜より小さいキーを持つデータのうち、最大のキーを持つデータ」というように指定し、一件ずつデータを読み込みます。もちろん、こういうときは、そのキーが、行ごとに、ユニークでなくてはなりません。
SELECT * FROM CTABLE
WHERE
CODE = (SELECT MIN(CODE) FROM CTABLE WHERE CODE > :CODE)
SELECT * FROM CTABLE
WHERE
CODE = (SELECT MAX(CODE) FROM CTABLE WHERE CODE < :CODE)
もちろん並べ替えたサブクエリの1件目。とするのも良いですね。
SELECT * FROM (SELECT * FROM CTABLE
WHERE CODE > :CODE
ORDER BY CODE)
WHERE ROWNUM = 1
SELECT * FROM (SELECT * FROM CTABLE
WHERE CODE < :CODE
ORDER BY CODE DESC)
WHERE ROWNUM = 1
キーが複数の項目からなる場合は、少々やっかいです。
SELECT * FROM (SELECT * FROM MULTIKEY_TBL
WHERE (( KEY1 = :KEY1 AND KEY2 > :KEY2) OR ( KEY1 > :KEY1 ))
ORDER BY KEY1, KEY2)
WHERE ROWNUM = 1
SELECT * FROM (SELECT * FROM MULTIKEY_TBL
WHERE (( KEY1 = :KEY1 AND KEY2 < :KEY2) OR ( KEY1 < :KEY1 ))
ORDER BY KEY1 DESC, KEY2 DESC)
WHERE ROWNUM = 1
以前は OR だとうまく PRIMARY KEY を使ってくれなかったのですが、ORACLE10.2G だとちゃんと使ってくれます。
下位バージョンでは USE_CONCAT ヒントを使えばいいのかな?
以前はこの方法を紹介してましたが、これだと FULLSCAN になってしまうので、あまりよくありませんね。
SELECT * FROM MULTIKEY_TBL
WHERE
KEY1 || KEY2 = (SELECT MAX(KEY1 || KEY2) FROM MULTIKEY_TBL
WHERE KEY1 || KEY2 < :KEY1 || :KEY2)