SELECTその2
SELECTに関して前頁で書ききれなかったことを.
通常SQLによる検索結果の表示順序には意味はない.ORDER BYは,SELECTによる選択結果を指定した属性をキーにしてソートするものである.以下はORDER BYを使用してglopsでソートしている.
benchmark=> SELECT name, gflops, n, nb FROM cluster, result_linpack benchmark-> WHERE id=cluster_id AND gflops > 9 benchmark-> ORDER BY gflops; name | gflops | n | nb ------+--------+-------+----- var | 9.271 | 17000 | 120 fuga | 9.456 | 20000 | 120 fuga | 9.575 | 20000 | 200 var | 9.597 | 18000 | 120 fuga | 9.598 | 20000 | 160 var | 9.619 | 20000 | 140 var | 9.666 | 20000 | 320 var | 9.78 | 19000 | 120 var | 9.781 | 20000 | 280 var | 9.88 | 20000 | 160 var | 9.977 | 20000 | 120 var | 10.06 | 20000 | 200 var | 10.31 | 20000 | 240 (13 rows)逆順にソートするには,DESCを指定する.以下は上の例を逆順にソートしている.
benchmark=> SELECT name, gflops, n, nb FROM cluster, result_linpack benchmark-> WHERE id=cluster_id AND gflops > 9 benchmark-> ORDER BY gflops DESC; name | gflops | n | nb ------+--------+-------+----- var | 10.31 | 20000 | 240 var | 10.06 | 20000 | 200 var | 9.977 | 20000 | 120 var | 9.88 | 20000 | 160 var | 9.781 | 20000 | 280 var | 9.78 | 19000 | 120 var | 9.666 | 20000 | 320 var | 9.619 | 20000 | 140 fuga | 9.598 | 20000 | 160 var | 9.597 | 18000 | 120 fuga | 9.575 | 20000 | 200 fuga | 9.456 | 20000 | 120 var | 9.271 | 17000 | 120 (13 rows)
通常SQLでの選択結果はマルチ集合,すなわち重複を許す.DISTINCT ONを使用すると,重複を削除してくれる.例えばresult_linpackでは,n,nb,cluster_idの組み合わせがキーなのでn,nbの組み合わせには重複が発生しうる.以下はnとnbの組み合わせの重複を削除している.
benchmark=> SELECT DISTINCT ON (n, nb) n, nb FROM result_linpack; n | nb -------+----- 10000 | 120 11000 | 120 12000 | 120 13000 | 120 14000 | 120 15000 | 120 16000 | 120 17000 | 120 18000 | 120 19000 | 120 20000 | 20 20000 | 40 20000 | 80 20000 | 120 20000 | 140 20000 | 160 20000 | 200 20000 | 240 20000 | 280 20000 | 320 21000 | 120 (21 rows)DISTINCT ONで重複を抑制しているのはnとnbの組み合わせであって,nあるいはnbのみの重複ではないことに注意.DISTINCT ONでフィールドを指定するのではなく,単にDISTINCTを指定すると,ターゲットリスト全体の重複をチェックする.上の例は,DISTINCT ONでn,nbを指定しているが,ターゲットリストはn,nbなので,単にDISTINCTと指定した場合と同じ結果となる.
benchmark=> SELECT DISTINCT n, nb FROM result_linpack; n | nb -------+----- 10000 | 120 11000 | 120 12000 | 120 13000 | 120 14000 | 120 15000 | 120 16000 | 120 17000 | 120 18000 | 120 19000 | 120 20000 | 20 20000 | 40 20000 | 80 20000 | 120 20000 | 140 20000 | 160 20000 | 200 20000 | 240 20000 | 280 20000 | 320 21000 | 120 (21 rows)
GROUP BYは,指定した属性でレコードをグルーピングする.これと集約関数を組み合わせると統計が取れる.以下はresult_netpipeにある計測結果をclusterのnameでグルーピングして,計測結果のレコード数とともに表示している.すなわちNETPIPEの計測結果をクラスタ毎に表示している.
benchmark=> SELECT name, count(*) benchmark-> FROM (SELECT * FROM cluster, result_netpipe benchmark(> WHERE id=cluster_id) AS temp benchmark-> GROUP BY name; name | count ------+------- foo | 360 fuga | 215 hoge | 254 var | 142 (4 rows)GROUP BYでグルーピングされたグループに対しては,HAVINGによりグルーピング結果の出力条件を指定できる.以下はGROUP BYの結果グルーピングされたレコード数が200より大きいものを表示している.
benchmark=> SELECT name, count(*) benchmark-> FROM (SELECT * FROM cluster, result_netpipe benchmark(> WHERE id=cluster_id) AS temp benchmark-> GROUP BY name HAVING count(name) > 200; name | count ------+------- foo | 360 fuga | 215 hoge | 254 (3 rows)
SELECTのターゲットリストでCASEを使用することにより,条件に応じた値を指定することができる.以下はnameの値に応じて出力をH,F,-を指定するものである.
benchmark=> SELECT CASE benchmark-> WHEN name='hoge' THEN 'H' benchmark-> WHEN name='fuga' THEN 'F' benchmark-> ELSE '-' benchmark-> END benchmark-> FROM cluster; case ------ H F - - (4 rows)結果の列名がCASEになっていることに注意.上の例ではELSEがあるのであり得ないが,条件にマッチするものがなければNULLが返される.CASEには制約があるがより簡単な別の形式もある.以下は先の例と等価である.
benchmark=> SELECT CASE name benchmark-> WHEN 'hoge' THEN 'H' benchmark-> WHEN 'fuga' THEN 'F' benchmark-> ELSE '-' benchmark-> END benchmark-> FROM cluster ; case ------ H F - - (4 rows)例から察しがつくように,この形式の制約とは,(CASEの直後の属性)=(WHENの次の値)という条件しか指定できないことである.
NULLIF(i,j)は
CASE i WHEN j THEN NULL ELSE i ENDと等価である.以下はnameが'foo'と一致する場合にはNULLを返し,一致しない場合はnameの値を返す.
benchmark=> SELECT NULLIF(name, 'foo') FROM cluster ; name ------ hoge fuga var (4 rows)
COALESCE(i,j,k,.....)は,i,j,kの値を順にチェックして,最初のNULLでないものを選択して出力する.以下はcpunum,cpuclock,memoryを順にチェックして最初にNULLでないものを出力する.
benchmark=> SELECT COALESCE (cpunum,cpuclock,memory) FROM cluster ;
case
------
256
256
512
(4 rows)
これは以下と等価である.
CASE WHEN cpunum IS NOT NULL THEN cpunum WHEN cpuclock IS NOT NULL THEN cpuclock WHEN memory IS NOT NULL THEN memory END
ALLは対象の全てを意味する.SOMEとANYは対象の少なくとも一つを意味する(※).以下はresult_linpackのすべてのレコードのgflopsの値以上のgflopsを持ち,かつid=cluster_idであるレコードをclusterとresult_linpackの直積から選択する.
benchmark=> SELECT name, gflops benchmark-> FROM cluster,result_linpack benchmark-> WHERE id = cluster_id benchmark-> AND gflops >= ALL (SELECT gflops FROM result_linpack); name | gflops ------+-------- var | 10.31 (1 row)以下はresult_netpipeのcluster_id=2であるレコードの中から,実行日付がresult_netpipeのcluster_id=3のレコードの内一つ以上と一致するものを表示する.
benchmark=> SELECT * FROM (SELECT * FROM result_netpipe WHERE cluster_id=2) AS t1 benchmark-> WHERE exec_date = SOME (SELECT exec_date FROM result_netpipe WHERE cluster_id=3);このSQLはかなり負荷が高いようだ.
※ SOMEとANYの違いはないらしい.

