ファイヤープロジェクト
SELECTその2
2003-12-14T21:50+09:00   matsu
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の違いはないらしい.
matsu(C)
Since 2002
Mail to matsu