ある列の値が平均未満の行を抽出
ある列、例えばcolの値が、そのテーブルのcolの平均値未満の行を抽出したい場合、ちょっと考えただけでもいくつかの方法が思いつく。
まずは、実行できないものから。
SELECT * FROM SomeTable WHERE -- WHEREの評価段階ではavgは計算できない col < avg(col)
SQLでは、WHEREの評価段階では集計関数は計算できないため、上のSQLはエラーとなる。
SELECT * FROM SomeTable WHERE -- 引数エラー的な col < avg(SELECT col FROM SomeTable)
これはavgの使い方を間違えているため、エラーとなる。
確かに、こんな書き方が出来てもいいんじゃないかなぁ、と思わなくもないけど。
上のような書き方は出来ないが、サブクエリ内にavgを移動させれば欲しい結果が手に入る。
SELECT * FROM SomeTable WHERE -- サブクエリを使えばOK col < (SELECT avg(col) FROM SomeTable)
ほかにも、ちょっとひねって、EXISTSとHAVINGを使った方法も考えられる。
SELECT * FROM SomeTable P WHERE -- ちょっとひねった方法 EXISTS(SELECT * FROM SomeTable C HAVING P.col < avg(col))
標準SQLではなくなるが、分解してしまうのも一つの手だろう*1。
-- 分解 declare @avg as float SELECT @avg = avg(col) FROM SomeTable SELECT * FROM SomeTable WHERE col < @avg
番外編として、自分で平均を計算しようとするような方法も・・・
-- ありえないと言い切れないところが怖い declare @total as int declare @count as int declare @tmp as int set @total = 0 set @count = 0 declare cur cursor for SELECT col FROM SomeTable open cur fetch cur into @tmp while @@fetch_status = 0 begin set @total = @total + @tmp set @count = @count + 1 fetch cur into @tmp end close cur deallocate cur SELECT * FROM SomeTable WHERE col < (@total / @count)
countやsumを自分で実装してしまうような人はそんなにいないけど、max、min、avgあたりはあり得ないとは言い切れないんだよなぁ。