ファイヤープロジェクト
カーソル
2003-12-29T13:30+09:00   matsu
SELECTではLIMITを使用しなければ,選択レコードを一気に出力する.これを任意の件数ずつ取り出すようにするには,カーソルを使用する.
カーソルは,SELECT文の結果に対してあわされるものである.通常はSELECT文による選択レコードは一度に出力されるが,カーソルを使用することで,選択レコードの中から,カーソルがあっているレコードのみ,あるいは,カーソルがあっているレコードから前方,あるいは後方に任意の件数のレコードを取得することができる.カーソルはトランザクションブロック内でのみ使用することができる.カーソルの宣言は以下.
benchmark=> \h DECLARE
Command:     DECLARE
Description: define a cursor
Syntax:
DECLARE cursorname [ BINARY ] [ INSENSITIVE ] [ SCROLL ]
    CURSOR FOR query
    [ FOR { READ ONLY | UPDATE [ OF column [, ...] ] ]
カーソル名cursornameは任意の文字列.SELECT文queryではSELECT FOR UPDATEも可.これを実行しただけではSELECT文の結果は出力されない.結果はFETCHを使用することで,任意の件数ずつ取り出すことができる.
benchmark=> \h FETCH
Command:     FETCH
Description: retrieve rows from a table using a cursor
Syntax:
FETCH [ direction ] [ count ] { IN | FROM } cursor
FETCH [ FORWARD | BACKWARD | RELATIVE ] [ # | ALL | NEXT | PRIOR ] { IN | FROM } cursor
カーソル名cursorはDECLAREしたカーソルから選択する.逆に言うと複数のカーソルをDECLAREしておいて,それらから名前を指定して取り出すことができる.directionにはFORWARDやBACKWARDを指定し,それぞれ次あるいは前のレコードを指定する.countは何件取り出すかを指定する.トランザクションを終了するとそのトランザクションで宣言したカーソルもなくなる.
SQL92ではカーソルはデータの取得だけでなく更新もできるらしいが,PostgreSQLでは取得のみである(READ ONLYカーソル).
まずカーソルを宣言する.
benchmark=> BEGIN ;
BEGIN
benchmark=> DECLARE cur1 CURSOR FOR
benchmark-> SELECT * FROM result_linpack ;
DECLARE
で,一件取り出してみる.
benchmark=> FETCH FORWARD 1 IN cur1;
   n   | nb  | cluster_id | gflops  | exec_date  
-------+-----+------------+---------+------------
 10000 | 120 |          4 | 106.848 | 2003-12-23
(1 row)
FORWARDは省略できる.
benchmark=> FETCH 1 IN cur1;
   n   | nb  | cluster_id | gflops  | exec_date  
-------+-----+------------+---------+------------
 11000 | 120 |          4 | 107.323 | 2003-12-23
(1 row)
BACKWARDを指定すると,カーソルは逆方向に動く.
benchmark=> FETCH BACKWARD 1 IN cur1;
   n   | nb  | cluster_id | gflops  | exec_date  
-------+-----+------------+---------+------------
 10000 | 120 |          4 | 106.848 | 2003-12-23
(1 row)
件数を指定しない場合は1件取得となる.
benchmark=> FETCH IN cur1;
   n   | nb  | cluster_id | gflops  | exec_date  
-------+-----+------------+---------+------------
 11000 | 120 |          4 | 107.323 | 2003-12-23
(1 row)
3件取得してみた.
benchmark=> FETCH FORWARD 3 IN cur1;
   n   | nb  | cluster_id | gflops  | exec_date  
-------+-----+------------+---------+------------
 12000 | 120 |          4 | 107.802 | 2003-12-23
 13000 | 120 |          4 | 108.091 | 2003-12-23
 14000 | 120 |          4 |  108.31 | 2003-12-23
(3 rows)
今,カーソルはn=14000のレコードにあるので,ここで1件BACKWARDで取得するとn=13000取得となる.
benchmark=> FETCH BACKWARD 1 IN cur1;
   n   | nb  | cluster_id | gflops  | exec_date  
-------+-----+------------+---------+------------
 13000 | 120 |          4 | 108.091 | 2003-12-23
(1 row)
NEXTは次のレコード,PRIORは前のレコードである.FORWARD,BACKWARDとの違いはよくわからない.
benchmark=> FETCH NEXT IN cur1;
   n   | nb  | cluster_id | gflops | exec_date  
-------+-----+------------+--------+------------
 14000 | 120 |          4 | 108.31 | 2003-12-23
(1 row)

benchmark=> FETCH PRIOR IN cur1;
   n   | nb  | cluster_id | gflops  | exec_date  
-------+-----+------------+---------+------------
 13000 | 120 |          4 | 108.091 | 2003-12-23
(1 row)
ALLを指定すると,残りのレコードを全て取得できるが,それをやるとカーソルを使用する意味がないような気もする.
benchmark=> FETCH ALL IN cur1;
...残レコードを全て出力...
カーソルの後始末は不要で,単にトランザクションブロックを閉じればよい.
benchmark=> ROLLBACK ;
ROLLBACK
matsu(C)
Since 2002
Mail to matsu