2004年12月21日
Class::DBIでMySQL4.1の空間拡張を使う (CREATE編)
アンテナ奪取での近隣アンテナ検索に、MySQL4.1の空間拡張を使う事に決めました。
ところが、MySQL4.1の空間拡張は、空間データ列がBLOB扱いで、SQL上での独自関数経由でないと内容が書き込めない/読み取れないのでClass::DBIと非常に相性が悪いです。
PostGISならまだSQL上では文字列扱いなので何とかなりそうなんですが…。
そこで、とりあえず次のような形でCREATEはできるようにしました。
Class::DBIのWikiページのCookbookを見ると、CREATE時にデフォルト値を設定する方法が紹介されてます。
これを応用して、次のような形でCREATE時の発行SQLを上書きしました。
__PACKAGE__->set_sql(MakeNewObj => <<'SQL');
INSERT INTO __TABLE__ (%s, pt)
VALUES (%s, PointFromWKB(Point(`lng`,`lat`),4326))
SQL
ここで、ptは空間データ列、lng/latは経緯度のスカラー値を突っ込む列としてます。
同じデータを空間データとスカラーで2重持ちする事になりますが、どうせSELECT時も空間データの値にAsText等の関数をSQL上で通してやらないと経緯度データが取れずに困る事になるので、それならもう別に持たせてやって、空間データは空間インデックスでの検索用途だけに使えばええやん、という発想です。
また、4326というのは世界測地系のSRIDです。
これで、lng/lat列に経緯度を突っ込んでClass::DBIをCREATEしてやれば、同時に空間データも計算されて挿入される、という事が実現できます。
注意しないといけないのは、Class::DBI::mysql等を用いてテーブル構造を自動取得させてやったりすると、そちら側で位置データ列ptを取得してSQL文に自動追加されてしまうので、pt列の2重指定になりエラーになってしまう事です。
空間インデックスを張るためには空間データ列はNOT NULL制約が必要になるので、テーブル環境の自動設定を行った場合、INSERTのSQLが発行されると必ずpt列は必ず指定されてしまい、回避できません。
面倒くさいですが、この場合はpt列を除いた列名リストを地道に__PACKAGE__->columnsで追加していってやってください。
後は、set_sql等で設定した独自のSQLで、pt列ベースの空間インデックスで検索した後、lng/lat列の値から経緯度を読み取ってやれば、SELECT部分も問題なしです。
残されるのはUPDATEだけですが、とりあえずうちの要件ではUPDATEは必要ないので、またおいおい調べていきたいと思います。
[composed and posted with ecto]
![[ここギコ!]](http://kokogiko.net/logo.png)



・ジオメディア忘年会行ってきました(宋さんへ:kokogiko)
・コンピュータは2進法が効率的でとかいう話(kokogiko)
・コンピュータは2進法が効率的でとかいう話(まぐろ)
・コンピュータは2進法が効率的でとかいう話(名無し)
・コンピュータは2進法が効率的でとかいう話(dokasen)
・コンピュータは2進法が効率的でとかいう話(dokasen)
・Google未オルソ衛星画像にぶった切られた我が母校(maeda)
・ジオメディア忘年会行ってきました(宋)
・ジオメディア忘年会行ってきました(kokogiko)