第 2 章 SQL Server 2008 で空間データを実装する (Beginning Spatial with SQL Server 2008)

 前章では,空間参照系の背後にある理論を紹介し,異なる種類のシステムが地球上の特徴を記述する方法を説明した.本章では,これらのシステムを適用して SQL Server 2008 における新しい空間データ型を使って空間情報を蓄積する方法を学んでもらう.

データ型を理解する

 SQL Server テーブル内のあらゆる変数,パラメータおよび列は特定のデータ型であるとして定義される.このことは SQL Server がどんな種類のデータ値をフィールドに蓄積されるか,いかにして使われるかを示している.いくつかの一般的に使われるデータ型を Table 2-1 に列挙・記述している.

Table 2-1. 一般的ないくつかの SQL Server データ型
データ型 使用法
char 固定長文字列
datetime 日付と時刻の値,精度は 3.33 ミリ秒
float 浮動小数の数値型
int  -231 から 231-1 までの範囲の整数
money 財務型,通貨型
nvarchar 可変長,ユニコード文字列

 SQL Server 2008 は特に空間データ型を保持する意図で2つの新しいデータ型を導入した.geography 型と geometry 型である.Table 2-2 参照.

Table 2-2. SQL Server 2008 での空間データ型
データ型 使用法
geography 測地ベクトル空間データ
geometry 平面ベクトル空間データ

 両者のデータ型は共に空間データを蓄積するが,互いに明確に区別され,異なる方法で使われる.SQL Server 2008 において空間データのアイテムを定義する時はいつでも,使う情報が geometry 型なのか geography 型なのかを蓄積するのに選択しなくてはならない.

注記 geometry という単語は本書においては2つの異なる意味を持つ.混乱を避けるために geometry (テキストフォーマットなし)の語句は地球上の特徴である Point, LineString および Polygon を指すことにする.geometry 型と言う場合は geometry データ型を指すことにする.本書ではこれ以降,この慣習を使うことにする.

空間データ型を比較する

 2つの空間データ型にはいくつかの類似点がある.

  • いずれも geometry の範囲内で空間情報を表現する.Points, LineStrings および Polygons である.
  • 内部的には,両データ型共に空間データを同じ形式のバイナリーデータストリームとして蓄積する.
  • どちらのデータ型からデータのアイテムを使う時でも,.NET フレームワークに基づくオブジェクト指向メソッドを使わなければならない.これの詳細については次章で述べる.
  • 両者とも同じ標準の空間メソッドを数多く実装しており,その種類のデータの計算の解析および実行を行うことができる.

 しかし,2つの空間データ型の間には多くの重要な違いも存在し,Table 2-3 に概要を示してある.データベース内のデータを使うために計画する方法に応じて,適切なデータ型を選択しなければならない.

Table 2-3. geometry 型と geography 型の比較
プロパティ geometry 型 geography 型
地球上での形態 平坦 丸い
座標系 投影(または平面) 地理的
座標値 デカルト (x, y) 緯度と経度
計測単位 座標系と同じ sys.spatial_reference_system で定義
空間参照識別 非強制 強制
SRID 初期設定 0 4326 (WGS 84)
大きさの制限 なし 半球以上のオブジェクトは生成不能
リングの方向 重要でない 重要

 これらの違いの特徴は,2つのデータ型の詳細を読むと,より明確になる.

Geography データ型

 geography 型の最も重要な特徴は,測地空間データを蓄積するということである.これは地球が曲面の形態をしていることを考慮している.geography 型を使って空間データを操作する時には SQL Server は結果を出力する際に角度演算を行っている.これらの演算は,問題となる空間参照系で定義される地球の楕円体モデルに基づいて計算される.例えば,仮に geography 型の地球の表面上の2つの地点を結ぶ直線を定義しようとする場合,その直線は参照楕円体に沿った曲線となるだろう.geography 型では,あらゆる2地点間の直線はすべて(その直線が LineString のセグメントであれ,Polygon リングの辺縁であれ)実際には大楕円弧となる.つまり,地球表面上の直線は参照楕円体の頂点および中心の両者を含む平面から形成される.これを図示したのが Figure 2-1 である.

座標系

 geography 型は,世界の三次元の球体モデルに基づいており,このデータ型を使って geometry を定義した地点の各々の位置を指定するには地理座標系を使わなければならない.地理座標系を使う時にはこれらの地点の座標は経度と緯度の角度で表現されることを銘記されたい.

計測単位

 geography 型が経度と緯度の角度計測を使って地点を定義するために,座標値は通常,角度で測定される.これらの角度座標は地点の位置を表現するのに有用であるが,地点間の距離やいくつかの地点で囲まれた面積を計測するにはあまり役に立たない.例えば,空間参照系 EPSG:4326 を使ってフランスのパリの位置を 48.87°N, 2.33°E と記述することはできる.同じ参照系を使ってドイツのベルリンの位置を 52.52°N, 13.4°E と記述することもできる.しかし,パリとベルリン間の距離を知りたい場合に,角度で答えを記述して 11.65° 離れていると言われても,役に立たないだろう.おそらく,それらの間の距離は 880 km とか 546 マイルとか言ったほうが,より役に立つだろう.

 これを考慮して,geography 型を使って空間データの任意のアイテムで計算を実行する時には,その結果は,空間参照系に関連する sys.spatial_reference_systems テーブルの unit_of_measure 列で指定した線形計測単位で返される.例えば,空間参照系 EPSG:4326 に使われる計測単位を調べるには,次の T-SQL クエリを走らせる.

 結果は次のとおりである.

 これにより,geography 型で蓄積され,EPSG:4326 空間参照系を使って定義されたデータに対して実行された任意の線形計算の結果はメートルで記述される,ということが分かる.先に与えられた座標に基づいてパリとベルリン間の距離を計算するには,次の T-SQL コードを実行することである.

 結果はメートルで表現される.

注記 上述の構文が理解できなくても悲観することはない.次章でこれを説明する.ただこのクエリが,パリとベルリンを表現する geography 型の points を生成すること,そしてこれらの最短距離を計算してくれることを知っていればよい.

 ほとんどの空間参照系はメートルに基づいており,geography 型を使って計算された距離は普通メートルで表記され,面積は平方メートルで表記される.

空間参照識別子

 geography 型を使ってデータのアイテムを蓄積する時はいつでも,そこから座標を取得する空間参照系に対応した適切な SRID を提供しなければならない.SQL Server 2008 はその計算において地球の曲面の関連するモデルに適用する空間参照系に含まれる情報を使い,適切な計測単位で任意の線形法で結果を表現する.提供された SRID はそれゆえに sys.spatial_reference_systems テーブル内の空間参照でサポートされるものの一つに相関していなければならない.

 仮に geography 型のデータを蓄積する時に異なる SRID を提供したなら,そのデータを使って取得したどんな方法でも,異なる結果を取得することになるだろう.なぜなら,その計算は異なる測地パラメータに基づいているからである.

大きさの制限

 技術的な限界から,SQL Server は geography 型で蓄積される一個のオブジェクトの最大サイズに制約を課している.この制約の効果とは,geography 型を使うすべての geometry は新規に生成されたものであれ計算の結果であれ,一つの半球内に適合しなければならないというものである.この文脈でいうところの半球とは,北半球とか南半球などの地球の所定の面を指すのではなく,地球上の任意の一点を中心とした地球表面の2分の1のことを指している.この大きさを超えるオブジェクトを生成しようとすると,次のエラーを受け取ることになる.

 この制限ぎりぎりを扱うには,巨大な geography オブジェクトをいくつかの小さなオブジェクトに分割して,それぞれが関連するサイズの限界以内に収まるようにすることだ.例えば,地球上の海面を表現するための単一の Polygon オブジェクトを持つのではなく,複数の polygon を定義してそれぞれが個々の海洋を表現するようにすればよい.組み合わせることで,これらの小さなオブジェクトは海洋表面全体を表現する.

注記 geography 型に課せられた制約は半球より大きな面を持つ geometry だけに適用されるのではなく,同じ半球状にないならどんな geometry にも適用される.例えば,geography 型を使って北極点と南極点の二つを表現する MultiPoint geometry を生成することはできない.

リングの方向

 前章で示したエラーメッセージを見直してみよう.無効な geography インスタンスの一般的な理由として「…ある polygon が誤ったリングの方向を持っている」とある.これは何を意味するのだろう?第1章で述べたリングは閉じた LineString であったが,Polygon geometry は一つかそれ以上のリングからなり,面の辺縁は Polygon 内部にあると定義している.リングの方向とは「方位」,または順序,つまりそこから Polygon がスタートするポイントを指している.

 geography 型は地球の測地モデルを定義しており,それは連続する曲面である.地図投影から想像で生成されるのと違って,そこには辺縁は存在しない.世界中を一方向に廻り続けることもできるし,スタートした位置に戻ることもできる.これが Polygon リングのポイントを定義した時の特徴になるのは,球体モデルを使う時,Polygon 内部に含まれるリングのどちら側なのか曖昧さが残る.Figure 2-2 を考える時,赤道周辺に描かれたポイントのシリーズがどの外部リングの Polygon のどちらを描いているのだろう.Polygon 内部に含まれる領域は北半球か南半球のどちらを表現しているのだろう?

 この曖昧さを解決するには geography 型を使って Polygon のポイントを定義する時に,SQL Server 2008 がその領域を Polygon 内部に含まれるリングのポイント間の経路の「左側」として扱うようにし,リングの「右側」にあるポイントは全て除外する.Figure 2-2 で与えられた例では,仮に想像の中で示された方向に向かってリングの経路に沿って歩くと,左側にある領域は北となり,示した Polygon は北半球を表現することになる.これを別の視点から考えると,宇宙から地球上の一点を直接見下ろしていると想像することになる.仮に反時計回りに囲まれたポイントのリングだとすると,それらのポイントは Polygon 内部に含まれる(そのリングの経路の左側に存在しなければならないからである).仮に,代わりに時計回りの方向のリングのポイントに囲まれているとすると,それらのポイントは Polygon の定義内部には含まれていないことになる.

注意 仮に小さな polygon リングのポイントを誤った方向で定義すると,その結果のオブジェクトは「内側と外側が入れ替わった」状態になる.地球表面の大部分を含めて,直線状のリングの小さな領域を除いて.これは,地球表面の2分の1以上をカバーできる geography 型は存在しないというサイズの制約を破壊することになるため,エラーを引き起こす.ある Polygon の内部を含める時は,反時計回りにポイントを定義するように注意されたい.それはその領域が,ポイントを結ぶ経路の左側に含まれるからである.

 geometry のスペースを切り取る領域を定義する内部リングにとって,リングの方向はどうなるのだろう?「内部」とか「外部」という分類は,連続した曲面の表面からなる geography 型のリングには簡単に適用できない.事実,geography 型の内部の Polygon はリングを何個でも含めることができ,それぞれが球体の空間を Polygon 内部に含まれるポイントに分割し,かつそれらのポイントは除外されている.これらのリング全てが外部リングまたは内部リングとみなすことができる.これを示すために Figure 2-3 に二つのリングを含む geography 型の Polygon の適切なリングの方向を示した.矢印は各リング内のポイントの方向を示しており,Polygon により囲まれる領域をグレーで示してある.

Geometry データ型

 geography 型と対照的に,geometry 型は空間データを平面上にあるものとして扱う.すべての空間演算の結果,二点間の距離は簡単な幾何学的手法を使って算出される.この平面アプローチは Figure 2-4 に図示した.覚えておくべき鍵となる原則とは,リングのポイント間に引かれた経路の左側の領域が Polygon 内部に含まれること,右側が除外されることである.

座標系

 geometry 型は平坦な二次元の平面上で作用し,その平面上の任意のポイントは一組のデカルト座標 (x, y) を使って定義される.その geometry 型は,次の座標系の型のうち任意の一つからの座標を蓄積するために使われうる.

投影座標系

 geometry 型は投影座標を蓄積するには理想的であり,x および y 座標のペアは投影空間参照系から取得された東座標値と北座標値を表現している.この例では,投影のプロセスは既に角度地理座標を平面上にマップ済みであり,その上で geometry 型が適用される.

地理座標系

 緯度と緯度の「非投影」geographic 座標は直接 geometry 型の y および x 座標にそれぞれ割り当てられる.これは非投影地理座標系のように見えるかも知れないが,実際には投影系の一例でもあり,それは正距円筒図法を生成するのに使われる手法だからである.

自然平面座標系

 これらの座標は x および y 値で表現される任意の地理空間データを表現するが,地球の特異的なモデルに関連しているわけではない.これらのデータの例は地域の調査の収集や小地域のトポロジー計画など曲率が無関係なもの由来なのかも知れないし,コンピュータ支援設計 (CAD) パッケージから取得されたもの由来なのかも知れない.

計測単位

 geometry 型を使う時,ポイントのデカルト座標は定義された軸,特に計測単位で表現された軸に沿った原点からそのポイントまでの距離を表現する.geometry 型は,その座標値に基づいた単純な平面計算を使うため,その結果は geometry 型を使ったいかなる演算も座標値自身と同じ計測単位で表現される.例えば,多くの投影座標系の北座標と東座標とはメートルで表現される.これはユニバーサル横メルカトル図法 (UTM) および多くの国立グリッド参照系にあてはまる.仮に geometry 型を使ってこれらの系から取得した座標に基づいて空間データを蓄積しようとすると,長さと距離もまたメートルで測定されることになる.仮にgeometry 型を使って面積を計算しようとするなら,その結果は,座標値を定義するのにどんな計測法が使われていようと,この例では平方メートルだが,二乗になる.仮にしかし,フィートで測定された投影空間参照系からの座標を蓄積しようとするなら,その結果はいかなる計算もフィートで表現され,面積は平方フィートになる.

注意 最初に,geometry 型は「非投影」地理型の座標値である緯度や経度を蓄積するのに使われる可能性があり,直接に y 座標と x 座標をマップすると述べた.しかし,緯度と経度は角度座標であり,一般に度数で測定されるということを思い出そう.仮に geometry 型を使ってこの方法で情報を蓄積すると,ポイント間の距離もまた度数で測定されることになり,Polygon で囲まれた面積は度数の二乗で測定されることになる.これはほぼ間違いなく,望む結果ではないだろう.だから geometry 型をこの方法で使う時には注意を払うこと.

空間参照識別子

 geometry 型は地球の曲率をまったく考慮せず,SRID 内で記述された計測単位にも関係しないため,異なる SRID を提供しても,geometry 型を使って取得される結果に違いをもたらすことはない.これは把握するのが難しい概念である.先の章で,座標のいかなる部分も,投影座標であれ地理座標であれ,関連する SRID と共に記述しなければならないと書いた.それは座標系が地球上の一点を参照できるようにするためである.仮に geometry 型を使って投影座標系からの座標を蓄積しようとすると,SRID が提供されたところで違いがないとはどういうことなのだろう?

 その答えは,SRID が必要なのは投影参照系であって,地球上の位置を一意に識別するために座標をまず定義するためである,ということになる.しかし,一度それらの値を取得してしまえば,全てのさらなる操作は,その上でデータを基本的な幾何学的手法を使って実行される.地球の曲率への対処方法についてのいかなる決定も,任意の地点が投影像の上に存在する場所を記述する座標の定義の過程で,既になされている.

 例えば,geometry 型を使う時,座標 (0, 0) 地点と座標 (30, 40) 地点間の距離は常に 50 単位になるはずであり,その座標系がどんな空間参照系を使っていようが,どんな単位で表現していようが無関係である.地点 (0, 0) と地点 (30, 40) で表現された実際の地球上の形態は問題にしている系によって変わってくるが,これは geometry 型のデータが計算に使われる方法には影響しない.

 geometry 型の空間オブジェクトを使って操作を実行するためには,各ポイントの座標を取得した空間参照系が何であるかは違いをもたらさない.すべて同じ系から取得する限りは.

一貫したメタデータを確保する

 結果に違いをもたらさないからと言っても,投影座標系に基づくデカルト座標データを蓄積するのに geometry 型を使う時は,関連する SRID を指定すべきであり,その由来する座標を使う空間参照を指定するためである.その空間参照系は重要な付加情報を保有しており,それらの座標を地球上の特定の位置に関連づけるものである.全ての座標セットと共に SRID を明示的に記述することは,この重要なメタデータを保持するだけではなく,異なる空間参照系を使って定義された空間データのアイテムの計算を誤って試みるのを防いでくれる.それは望まない結果をもたらすからである.

付記 sys.spatial_reference_systems テーブルは単に測地空間参照を保持するだけであり,それは geography 型を使って計算を実行するのが必要だからである.投影参照系に適切な SRID を見たければ,次のウェブサイトを見るとよい.http://www.epsg-registry.org/

非測地空間データの保存

 geometry 型は平面座標を蓄積し,標準的なユークリッド法を使って SRID を必要とせずに計算を実行するため,x 座標と y 座標で記述できるならいかなる空間データでも蓄積でき,地球の形態の特定のモデルを必要としない.これは倉庫内のアイテムの位置を保有するような,有限の小規模アプリケーションには有用である.この場合,位置はローカルの原点からの x および y 座標により定義される.地球の表面全体に適用される投影座標系を使う必要はない.

 geometry 型はまた,ある座標系で表現された他の自然平面幾何データを蓄積するのにも使われる.例えば,仮に製造業の行程の詳細な構成要素を蓄積したデータベースを持っているとすると,geometry 型の列を各構成要素の形態を記録するのに使うことができるだろう.

 geometry 型を使ってこのような方法で空間データを記録する時,どんな幾何的形態であっても SRID 0 を使って定義すべきである.これは SQL Server に,その座標は特定の空間参照系に由来するのではなく,特定の計測単位を持たない座標値として扱うようにと教えることである.

リングの方向

 Figure 2-5 を考慮すると,それは Polygon リングを図示したものであり,平面上に geometry 型を使って定義された北半球を表現している.

 geography 型を使った同様の Polygon と違って(Figure 2-2 に示したが),Figure 2-5 における Polygon に含まれる領域は明確である.たとえポイントが時計回りをなすような,リングの方向が逆であっても,そのリングに囲まれた領域はなおも北半球を表現する.geometry 型においては,リングの方向は,Polygon リングのポイントがその中で方向を特定されるのだが,重要ではない.実務上の用語でいうと,次のポイント座標で定義されるリングは

例えばだが,次のポイントで特定する扱われ方と同様に扱われる.

 Polygon で切り取られる空間の領域を含む内部リングを定義する時,これらは時計回りであれ反時計回りであれ指定できる.ただし,外部リングの内部に完全に収まっている限り,あるいは,互いに交差したり一方が他を包含していない限りではあるが.

適切な空間データ型を選択する

 2つのデータ型の間の主な違いを見てきたところで,どんな状況ではどちらを使うべきなのかと,おそらく戸惑うだろう.それは重要な疑問であり,決定的な答えは存在しないが,次のリストがいくつかの一般的なガイドラインとなるだろう.

  • 仮に緯度と経度のデータ(例えば GPS 装置由来,Google Earth 由来,または他のウェブ由来など)を使う場合は,geography 型を使うこと.デフォルトでは 4326 SRID を使っている.
  • 仮に投影座標系を使っている場合には(例えば平面の地図を収集しているなど)geometry 型を使い,地図投影および基準点に使われている SRID を使うこと.
  • 仮に地球に対して特に何も定義されていない x, y データを使っている場合には,geometry 型を使い,SRID は 0 とすること.

 これらの一般的な規則に加えて,多くの追加因子が存在し,この節で記述しているが,意思決定の助けとして考慮すべきである.適切なデータ型の選択は,空間データベースの効率的な設計の確保の最初の一歩であり,ゆえにこれらの要素を決定する前に注意深く吟味すること.

一貫性

 SQL Server 2008 において空間データの複数のアイテムを使った操作を実行するために,すべてのデータは同一の空間参照系,同一のデータ型を使って定義されなければならない.geometry 型と geography 型のデータを同一のクエリ内で混在させることは不可能であり,同一のデータ型であっても異なる SRID を使って定義されたアイテムの操作を実行することも不可能である.仮にそのようなことをしても,SQL Server は NULL を返すだろう.

 仮に,既に空間データが存在していて,そのデータをシステムに集積したいなら,ゆえにデータが既に収集されたフォーマットに適したデータ型を使うべきである.例えば,仮に National Grid of Great Britain 系から収集した投影データを持っているなら,そのデータは geometry フィールドに蓄積すべきであるし,SRID は 27700 を使うべきである.仮に GPS システムから収集した緯度座標と経度座標を使っているなら,geography 型と SRID 4326 を選択すべきである.

付記 SRID は座標値がその中で定義されたシステムについての情報を提供することを思い出そう.それはシステム自身について言及するものではないが.ゆえに単純に,異なる空間参照内でそれらを表現する目的で,異なる SRID 値を既存の座標に提供することはできない.ある空間参照系から別の系へと座標値を変換するには,データを再投影しなければならない.SQL Server 2008 はいかなる再投影メソッドも提供していないが,数あるサードパーティ製のツールはこれが可能である.例えば OGR2OGR は OGR Simple Feature Library (http://www.gdal.org.ogr/index.html) の一部である.

精度

 geometry 型は地球の表面を平面に投影した投影系に基づく平面モデルを使う.先の章で説明したように,いかなる三次元表面の投影プロセスも,この方法ではそこで表現される特徴はある程度の歪曲に至り,それは面積や形状,距離あるいは方向に影響してくる.これはつまり,geometry 型を使うということは,特定の空間操作の結果は必ず歪曲するということであり,使われる投影法,特にその上での計算が基づく地球の表面の一部に依存するということである.

 一般的に言えば,投影される表面積が大きくなるほど,発生する歪曲は大きくなる.小さな面積にわたるこれらの歪曲の影響はかなり最小化されるにも関わらず,大規模なアプリケーションや地球規模のアプリケーションにとっては,geometry 型を使って取得したいかなる結果の精度も,geography 型を使って(そこには投影による歪曲が存在しない)取得した結果と比較すると,決定的なインパクトがある.小さな空間領域のみをカバーする多くのアプリケーションにおいては,米国の特定の州の内部を含むようなものは,関連する州の平面を投影する geometry 型を使って実行した計算結果は,十分に正確だろう.しかし,精度を犠牲にした投影法に基づく演算は,長距離に渡るほど,geography 型の方がより適した選択肢となってくるだろう.

世界の果て

 地球自身とは違い,投影法の結果として歪曲が発生する極端な例として,投影地図には「果て」が存在することである.geometry 型を使って投影空間データを蓄積する時,辺縁と交差するデータを定義するのに必要な状況を特に考慮する必要がある.典型的に発生するのは,geometry あるいは計算結果が 180th 子午線や地球の両極のいずれかと交差する時である.

 これらの歪曲が geometry 型を使った計算に影響する方法を説明するため,バンクーバーと東京間の最短直線距離を計算することを考えてみよう.平坦な geometry 型はグリニッジ本初子午線を中心とした投影法に基づいており,その結果は Figure 2-6 に示したように見えるだろう.

 対照的に,geography 型は連続した,地球の球体モデルを使い,そこには投影の結果として紹介した辺縁は存在しない.東京-バンクーバー間の最短距離として geography 型を使って得られた結果は Figure 2-7 に示したようなものになる.

 Figure 2-6 と Figure 2-7 に示した経路を比較すると,geometry 型の結果は,地図の境界を超えることができないために,より長い経路を描き,アメリカ全土,ヨーロッパ全土およびアジア全土を横切っていることが見えてくるだろう.対照的に,geography 型を使って取得された結果は太平洋を横切る最短経路を示しており,実際の地球の球体に基づいた正確な答えを表現している.

 これらの課題のさらなる説明は,所与の投影において地図の辺縁を拡張して geometry インスタンスを定義しようとする時に発生する.Figure 2-8 はロシアを表現する Polygon geometry をハイライトしてあるが,グリニッジ本初子午線を中心とした正距円筒図法として描いてある.

 ほとんどの Polygon が東半球に含まれるにも関わらず,ロシアの最北東地域(チュコトカ自治区)は実際に地図の辺縁と交差しており,西半球にも表れている.この投影法に基づく geometry 型を使うことは,ロシアを単一の Polygon geometry を使ってこの方法で表現することが不可能であるということである.代わりに,各々の形態を表現するには二つの要素を含む MultiPolygon geometry を使う必要があり,オリジナルの形態を二つに分割された地図の辺縁で生成されたものである.

 本章で提示された問題の両者は,geometry 型のための適切な空間参照系を選択することで,いくらかの範囲で緩和しうる可能性があり,その中で問題の特定の geometry は地図の辺縁と交差しなくなる.そのような投影の例として Figure 2-9 を示す.しかし,これは一つの特定例の問題を回避する一方で,完全には解決していない.つまり,仮に新しい地図が異なる投影法で生成されたとしても,今度は新しくできた辺縁の周辺の局在が常に問題となるだろうからである.

 仮に投影地図の辺縁と交差せざるを得ない geometries の状況を扱うことを期待するなら,データを蓄積するには geography 型がよりましな選択肢となるだろう.

表現

 geography 型は地球の三次元モデルを操作するため,仮に geography 型を地図で表現しようとすると,まずそれを投影する必要がある.以前議論したように,これは歪曲をもたらす.Figure 2-7 で与えられた例のように,geography 型は正確に2点間の最短直線経路を叩き出すが,仮にその結果を投影地図に表示しようとすると,この「直線」は歪曲されカーブして表示されるだろう.この歪曲の正確な効果は使われる地図投影の特性によって異なる.

 Figure 2-9 は Figure 2-7 で示したのと同一の東京-バンクーバー間の経路を描いてあるが,メルカトル図法を使って投影してあり,150° 経線を中心としてある.geography 型を使って計算した経路は球体にプロットするとまっすぐの線分として見えるが,平面の地図上ではカーブして見える.これは投影による歪曲効果による.

付記 しばしば大楕円弧を見るだろう.geography 型における2点間の最短経路であるが,目的地間の航空機の取る最適経路を図示するために航空便に使われる地図上では(Figure 2-9 に示すように)曲線として描かれる.

 逆に,geometry 型は既に平面上に投影されたデータに基づいているため,地図上に結果を表示するにあたって,さらに歪曲を導入する余地はまったくない.geometry 型における「直線」がまっすぐであるのは,地図上に描かれた時に限られる.その地図とは,地点が取得された空間参照系と同一の投影法を使って投影されて提供されたものである.

 仮に地点間の直線を表現しようとしてデータを使うつもりなら,そしてその線を地図上でもまっすぐに投影したいなら,geometry 型を選択すべきであり,その上に結果の表示される地図に対応する空間参照を選択すること.

パフォーマンス

 球面演算の実行にはデカルト演算よりも多くの計算資源を使用する.結果として,geography 型を使った楕円体モデルの空間演算は geometry 型を使う同等の操作よりもはるかに計算量が多くなる.これは地球の測地モデル,例えば距離や長さ,あるいは面積などの地理オブジェクトなどに基づく指標を計算しなければならない geography 型にのみ影響する手法である.地球のモデルを考慮する必要がない場合,例えばオブジェクトのポイント数を数える場合や特徴を表現するのに使う geometry の種類を記述する場合でも,物体の属性を返すメソッドを使ういかなる時でも,geography 型と geometry 型の間でパフォーマンスに違いはない.

標準への準拠

 次のウェブサイト http://www.opengeospatial.org/ によると,Open Geospatial Consortium (OGC) は「非営利,国際的,自発的なコンセンサス標準化機構で,地理空間および位置ベースのサービス標準化の発展を目的とする」.OGC は多くの空間データを扱う業界全体の標準を管理する.これらの標準に従うことで,異なるシステムでもコアレベルの一般機能を確保でき,それは空間情報がさらに簡単に異なるベンダー間やシステム間で共有されることを意味する.2007 年 10 月に,Microsoft は OGC に主要な一員として参加し,SQL Server 2008 に実装された空間データ型は OGC により定義された標準に拠るところ大であった.

 geometry 型は SQL Specification v1.1.0 (http://opengeospatial.org/standards/sfs) のための OGC Simple Features に従い,標準に合致させるために必要なメソッドを実装する.

 geography 型は geometry 型と同一のメソッドを多く実装するが,要求された OGC 標準には完全には従わない.

 こういう訳で,仮に SQL Server 2008 において,認められた OGC 標準に準拠する空間メソッドを使用するのが重要であるなら,geometry 型を使用すべきである.

空間データはどのように蓄積されるか

 geometry 型および geography 型は共に可変長データ型である.これの意味するところは,int 型や datetime 型のような固定長データ型とは対照的に,空間データの蓄積に実際に必要なストレージの量は,データの記述するオブジェクトの複雑性に依存するということである.

 SQL Server 2008 はgeometry 型および geography 型を含む情報をバイナリーデータストリームとして蓄積する.各ストリームは,記述された geometry の種類,使われる空間参照系,およびオブジェクト内の頂点の全体の数などの基本情報を定義したヘッダーセクションで開始される.このヘッダーはその直後に geometry 内の各 x および y 座標値(または経度・緯度)が続き,8 バイトのバイナリーフォーマットで表現される.オブジェクトがその定義内に持つ頂点が多いほど,このバイナリーストリームも長くなり,それゆえに必要なストレージスペースも大きくなる.

注記 SQL Server 2008 は各座標を倍精度浮動小数点型で蓄積し,それは IEEE バイナリ浮動小数点演算標準 (IEEE 754-2008) に準拠している.このフォーマットは浮動小数点を 15 桁の有効数字で蓄積することを可能とする.つまり,サブミリメートルの精度で一般にはどの位置でも十分な精度で記述できる.

 次のリストで空間データのいくつか一般的なアイテムを蓄積するのに必要なストレージスペースの例を提供している.

  • 2つの座標値で定義された一個の Point geometry は通常 22 バイトのストレージスペースを占める.
  • 2つの Point で定義された1個の LineString は最小で 4 つの座標(緯度と経度,または x 値および y 値で始点と終点からなる)を保持しており,38 バイトを占める.
  • 1個の Polygon geometry の占めるスペースは,マークアップする頂点の数に依存して変動する.Polygon により定義されたどんな内部リングも Polygon を蓄積するために必要とされるスペースを増加させる.

 geometry または geography オブジェクトに使われるデータストレージスペースには,特異的な最大サイズというものは存在しない.しかし,SQL Server 2008 にはどんな種類の巨大なオブジェクトであれ,全体の制約というものが存在し,それは 231-1 バイトが上限である.これは varbinary(max) 型や varchar(max) 型のようなデータ型と同等の制約であり,データの各個別のアイテムにとってのほぼ 2 GB に匹敵する.この制限を超過するには,大変に複雑な geometry オブジェクトを保存しなければならない!もし必要なら,多くの個別のオブジェクトが許されたサイズ内に適合するまで,複雑な geometry を分解する,と覚えておくとよい.

チップス T-SQL の DATALENGTH 関数を使って,任意の geometry および geography データのアイテムの蓄積サイズに使われるバイト数の値を見ることができる.

データ型間の変換

 geometry 型が,投影座標系,地理座標系あるいは自然平面座標系を使って定義される geometries を蓄積するために使われることを思い出そう.対照的に geography 型は,地理座標系を使って定義される geometries を蓄積するためだけに使われる.両者の空間データ型は地理座標データを蓄積するのに使われるため,geography 型を使って蓄積されたいかなるデータでも,代わりに geometry 型を使って表現できる.しかし,二つのデータ型の間で変換するために CAST 関数や CONVERT 関数を簡単に使うことはできない.仮に次のクエリを走らせて試してみよう.

 だが,次のエラーが返ってくるだけだ.

 そのエラー記述は,露骨な変換が許可されていないこと,つまり,それぞれのデータ型の扱いの含意を理解するのを確保するよう SQL Server により故意の制約が課せられていること,そして,意図せずデータを交換しないことに注意されたい.しかしこのような場合がある.geometry 型で利用できる関数が存在して,geography 型を使ってデータが蓄積されているのにその型では利用できない関数がある場合には,データ型相互間でのデータ変換が有用である.geography 型から geometry 型へ変換するためには,どちらのデータ型のアイテムの値であっても,バイナリーストリームとして表現できるという事実を代わりに活用することができる.次の例では,geometry 型変数 @geom は geography 型変数 @geog のバイナリーストリーム表現に基づいてセットされる.

 すべての geography 型のアイテムが geometry 型として表現できる一方,すべての geometry 型のアイテムが geography 型として表現できるわけではない.geometry 型から geography 型に値を変換するためには,存在する geometry 型のインスタンスの x, y 座標値は,「必ず」サポートされる測地空間参照系から緯度と経度の座標を取らなければならない.また,そのデータは必ず geography 型の必要とする他の全てに従わなければならない.例えば,リングの方向や大きさの制約などである.これらの設定が全て適合していれば,geometry 型インスタンス @geom のバイナリー表現から geography 型インスタンス @geog を生成することができる.

 しかし仮に,何も蓄積していないとか,投影座標系からの東座標だけとか,あるいは他の非測地データの場合,それは geometry 型でしかデータを蓄積できないということになり,geography 型に変換することはできない.

注意 geometry 型と geography 型の間で空間データのアイテムが変換されるようなケースというのは,比較的まれである.技術的に可能であるとしても,常に論理的に意味を成す訳ではない.もしデータ型の間で変換する必要を感じたなら,それは空間データのあなたの設計が間違っていることを示唆している.

テーブルを空間的に有効にする

 適切な空間データ型を選択したら,空間データを蓄積する計画のために SQL Server のテーブルに列を追加しなければならない.二つの方法がある.新規にテーブルを作成するか,既存のテーブルに新たに列を追加するかである.

テーブルの新規作成

 SQL Server データベース内に空間データの蓄積を可能にするために必要な特殊な属性も機能も存在しない.ただ必要なのは,最低一つの geography 型か geometry 型の列を含むことである.geography 型も geometry 型も既に登録済みであるため,T-SQL の CREATE TABLE ステートメントを使ってgeography 型か geometry 型のフィールドを含むテーブルを作成すればよい.次の通り.

 この例では,二つの列,つまり CityName と CityLocation を持つテーブルを作成しており,前者は 255 可変長文字列を保持し,後者はその都市に関連する空間データを保持するのに使われ,geometry 型である.

既存のテーブルへの追加

 SQL Server の空間機能を使う利点の一つは新しい geometry 型または geography 型の列を既存のテーブルに追加できることであり,空間情報をシームレスに既存のデータアイテムと一緒に集積できることである.

 既存のテーブル Customer は次の顧客情報のフィールドを持っていると仮定する.

 今度はこのテーブルに付加的な空間フィールドを追加して,各顧客の住所を記録したいと仮定する.特に問題なく,ALTER TABLE ステートメントを使って他の全てと同様に geography 型でも geometry 型でもフィールドを既存のテーブルに追加することができる.次の通りである.

 この方法でテーブルを拡張することにより,既存の顧客データと共に空間メソッドを使うことが可能となり,何名の顧客が確保したエリア内部にいるのか,ある特定の顧客が最も近い店舗からどれだけ離れたところに住んでいるのか,というような疑問に答えることができるようになった.

共通 SRID を強制する

 ある地点の座標は空間参照系が与えられた時にのみ意味をなす.SQL Server 2008 は同一の列の中に異なる空間参照由来のデータオブジェクトを蓄積することを許可しているが,機能を実行する時には,すべての空間データアイテムは同一の空間参照を使って定義されなければならない(例えば同一の SRID を持つなど).異なる系由来の座標を使って演算を実行しようとすることは,異なる通貨の金額の合計を算出しようとすることに例えることができる.

25 ドル足す 12 ポンドは 37 … 何だって?

 このような無意味な計算を偶発的に実行してしまうことを避けるため,SQL Server は異なる空間参照系で定義されたデータの計算を許可していない.どんなメソッドを使っても,かかる結果は NULL になる.

 仮に列内に一つの特定の空間参照系だけに基づいたデータしか蓄積しないと分かっているなら,その列に制約をつけることで同一の SRID を全アイテムに強制することができる.次のように,ADD CONSTRAINT ステートメントを使用するだけである.

 この例では enforce_srid_geographycolumn と呼ばれる制約条件をつけた.これは Customer テーブルの CustomerLocation フィールドに挿入されたすべての空間オブジェクトは SRID 4326 を使うよう定義するのを強制するものである.仮に異なる SRID に基づく geography  型のオブジェクトを挿入しようとすると,次のようなエラーを受け取ることになるだろう.

 結果として,この列由来のいかなる二つのデータアイテムを使っても計算を実行できるが,それは同一の空間参照系に基づいて定義されていることを知っている場合である.

要約

 本章では,SQL Server 2008 が geometry 型および geography 型の空間データを実装する方法について学んだ.

  • geography 型は測地空間データを使い,地球の曲率を説明する.
  • geometry 型は平面の空間データを使い,そこでは全てのポイントが平面上にある.
  • 適正な近似を選ぶ際に考慮すべき因子は多く存在する.与えられたアプリケーション,精度,表現,標準への準拠および存在するすべてのデータの一貫性である.
  • 内部的には SQL Server は空間データをバイナリ値のストリームとして蓄積する.
  • 既存のテーブルに空間データを追加するには ALTER TABLE を使うか,T-SQL 構文で空間データを扱えるテーブルを CREATE TABLE を使って生成する.
  • 空間データ列に挿入する際には,確実に SRID を持つデータだけを確保するよう制約を追加できる.

1920年から2015年までの都道府県別の5歳階級別人口推移

1920年から2015年までの都道府県別の5歳階級別人口推移

 e-Stat を渉猟していると面白いファイルを見つけた.国勢調査は 1920 年から開始されており, 2020 年 3 月現在では最新の調査結果は 2015 年のものである.20 回分の人口データが一つのファイルにまとめられており,グラフ化するには格好のデータである.

 年齢(5歳階級),男女別-都道府県(大正9年~平成27年)というファイルである.リンク先のページにはファイルが 3 つあるが,最後のものが最も粒度が細かいので,これをグラフ化する.

年齢(5歳階級),男女別人口-都道府県(大正9年~平成27年)
年齢(5歳階級),男女別人口-都道府県(大正9年~平成27年)

“1920年から2015年までの都道府県別の5歳階級別人口推移” の続きを読む

国勢調査から5歳階級の人口推移を調べる

日本人口の年齢階級推移(国勢調査より筆者作成)

 人口統計は最も重要な基幹統計の一つである.総務省の e-Stat は確かに有用であるが,かゆいところに手が届かない.例えば「市区町村ごと,年齢5歳階級ごとの人口構成の国勢調査ごとの推移を知りたい」という要求には全く無力である.

 主として技術的な理由によるものと,統計調査の粒度の細かさによる.技術的な理由としては,データベースの画面表示セル数の上限を容易に超えてしまうデータ量になってしまうことである.しかし,根本的な理由は調査の粒度の細かさである.

 2005 年以前と 2010 年以降とでは調査の精度が違う.今後は高精度なデータファイルが e-Stat に掲載されていくものと思われるが,2005 年以前に関しては都道府県より細かい粒度は存在しない.そこを求めると手作業になってしまい,現実的ではない.国立社会保障・人口問題研究所ならデータを持っているかもしれない.

 2020 年は国勢調査の年にあたる.総務省にはできるだけ細かい粒度でのデータ掲載を望むものである.

“国勢調査から5歳階級の人口推移を調べる” の続きを読む

はたらくオブジェクト

Range オブジェクト編

「おい,新米 Range オブジェクト!何ボーッと突っ立ってんだよ」
「す,すみません!」
「お前,名前は?」
「は,はい.myRng1と申します.よろしくお願いいたします」
「仕事に来たら,まず名乗れ.それがここの流儀だ」
「それから,自分の職域も一緒に言うんだ.わかったか?」
「は,はい」
「最初に書いてあるだろ?Option Explicit ってな.俺も詳しくは知らねぇが,あのルールは絶対だ.名乗らない奴に居場所はない…ほら,仕事が来たぞ」
「何い?誰だ,こんな糞コード書いたのは?ワークシートに何回アクセスさせる気だよ,全く…ほれ,ここからあそこまで走って値を取ってこい」
「ここからあそこまでって…えーっ?本気で言ってます?」
「何言ってるんだ?ワークシートにアクセスするような力仕事は新米 Range オブジェクトの役割と相場が決まってるんだ.さあ行った行った」


「ぜえ,ぜえ…取ってきました」
「おう,お疲れさん.値は取れたか?」
「はい,取れました」
「じゃあ次は,あそこにいる Range オブジェクトに,値を一個ずつ渡せ.えーと,名前は何だったかな.そうだ,myRng2 とか言ったな.おーい,myRng2 さんよ,ちょっと来てくれ」
「はい,myRng2 ですが,何か御用でしょうか?」
「えーとだな,この新米 Range オブジェクトから値を受け取ってやってくれ」
「お安い御用です.で,その後は?」
「あそこの ListObject オブジェクトに値を渡してほしいんだ.あ,Criteria1 のタグ,忘れないでくれよ」
「は~ん,さてはテーブルにフィルターを適用する気ですね?」
「参ったな,何でもお見通しかよ…まあ頼むわ」
「承知しました.さて,myRng1 さん,よーく見ていてくださいね」
「うわ,何この高速ループ!僕の持ってきた値,全部一個ずつ持って行ってしまった…」

ListObject オブジェクト編

「いらっしゃい,私は ListObject. テーブルとも言われてるのよ.さあ,どのプロパティを選んでくださるの?」
「今日は AutoFilter メソッドをお願いしますね」
「かしこまりました.どの Field かしら?」
「2と書いてあるから 2 番目ですね.Criteria1 タグはこれです」
ボワン
「あっ,ListObject さんが変身した?」
「やあ,僕は AutoFilter オブジェクトだ.フイルター結果を持っていってくれるかな?」
「さっきまでテーブルだったのに,どうして?」
「そんなに驚かなくてもいいだろ?オブジェクト指向プログラムの世界では当たり前のことだよ」
「おーい,myRng1 君!…駄目だ,ショックで気絶してる.仕方ないなあ,別の Range オブジェクト呼んでくるかな.myRng3 さん,いる?」
「ハイハイ,どうしました?」
「フィルター結果を持っていってほしいんだけど,新米くんが気絶しちゃってね」
「いきなり仕事をそんなに押し付けるからでしょうが」
「まあ,そう言わずに頼むよ」
「ハイハイ,分かりましたよ.ただね,梱包がややこしいんですよ」
「と言うと?」
「DataBodyRange プロパティと SpecialCells プロパティの重なるところだけ梱包しないと行けないんです」
「うーん,難しいな」
「…では,あれ,使っちゃいます?」
「あれか…」
「さてさて,取り出したるは,Intersect 関数でごさいます.二つの集合の重なったところだけを取り出す道具にございます.専門的には論理積を取ると申しますが,要は AND 演算子でございます」
「AutoFilter 節は今日も健在ですね.ではフィルター結果,頂いていきますね」

エラー処理編

「…あれ,Intersect関数の戻り値がありませんね」
「ホントだ.どうしよう?」
「このままじゃコードが止まっちゃいますね」
「うーん…じゃあ,条件分岐で myRng3 さんが Nothing の時の処理を加えますか」
「どうするんですか?」
「何もしません」
「え?」
「ですから,戻り値が普通に存在する時の処理は Else 節に書きます」
「そんな無茶苦茶な」
「いえ,これが通常の対応です」
「分かんね~.で,Then 節に入った場合はどうなるんですか?」
「そのループは無視されて,ループカウンターが一つ増えます.そしてループの最初からやり直します」
「つまり,リセット」
「そのループはなかったことにされるわけです」
「はああ…何か空しくなってきた」
「まあそう言わずに.これも仕事ですから」
「何かやりきれない」
「まあまあそう落ち込まずに.ループカウンターが増えると気分も変わりますよ」
「そんなもんですかね」
「大丈夫です.さあ行きましょう」

動的配列編

「おや,myRng3 さん,今日は元気がないね」
「いやあ,AutoFilter さんに説教されちゃったよ」
「ああ,あの人は笑いながら人を切るから…それはそうと,今日は何の値を持ってきてくれたんだい?」
「そうそう,Range 型の配列なんだけど,これ,どうする?」
「任せて…まずデータ数を見ないとね.ちょっと失礼」
「あっ,そこは…」
「ごめん.Rows.Count 取らせてもらった」
「もう…」
「仕事なんだから文句言わないでね.よし,では魔法の呪文,Redim Preserve!」
「あ,ここでもループが!動的配列さんの数が増えていく…動的配列さんから触手が…」


「うわあああ,そんなに触手であちこち触らないで!」
「ごめんね,これが僕の仕事なんだ…君の中から必要な値を取る…そして,次の担当者に渡す.これが僕の仕事…」
「うう,何だか頭の中全部見られた気がする」
「大丈夫だよ,必要な値しか取ってないから」
「そういう問題じゃない!」
「何か問題でも?君も僕も,データを次の担当者に渡すのが仕事だろ?」
「そうだけど…」
「個人情報保護だなんて無粋なこと言わないでよ.そこは僕らの管轄外」
「うう,僕らオブジェクトに人権はないのか…」
「ありがとう,必要な値は全部取れたよ.お疲れ様…あれ,myRng3 さん?顔が真っ青だよ」

Series オブジェクト編

「ああ疲れた.コードを読むと,僕の仕事はここまでだな.動的配列さんが次に何するか見物でもしてよう」

「うう,さすがにこれだけデータを溜め込むと体が重たいな…早くSeriesさんに渡そ」
「いらっしゃい.私は SeriesCollection. ユーザーからはデータ系列と呼ばれてるの」
「お久しぶり.元気にしてた?」
「さっきも会ったところでしょ!…ところであなた,また太った?」
「相変わらずきついなあ…データを渡したらすぐ痩せるんだから大丈夫だって」
「ふふっ」

「何かあの二人,楽しそうだな.僕も早く仲間入りしたいよ…」

「さて,仕事しましょ.今回は何のデータ?」
「うーん,タグを見ると『夕張市』って書いてある」
「ああ,あの財政破綻した街?噂で聞いたことはあるわね.何でも公債費比率が 80 % になってしまって行政サービスが切り詰められてるって」
「ほんとかい?ちょっとデータを覗いてみようか」
「こら,職権濫用!」
「堅いこと言うなよ.ちょっとだけだから」
「もう…今回だけは見逃してあげるけど,今度やったらイミディエイトウィンドウに告発するからね」
「…うわ,本当だ」
「マジ?…あら,ここ2年間は 80 % 近くに張り付いてるわね」
「てか何で覗いてるの」

「…ええと,何の話だっけ?」
「はいはい,仕事仕事」
「何か解せないけどまあいいや」
「じゃあ,行くわよ.ふーんっ!」
ポン!
「SeriesCollection さんが Series ちゃんを産んだ…何度見ても感動するなあ」
「そんなに感動するところかしら?さあ Series ちゃん,動的配列さんから値を受け取って」
「相変わらず冷たいねえ.はい,データ.Name プロパティと XValues プロパティ,Values プロパティだよ.後の二つは重いから気をつけて」
「ありがとう.はい,受領証」
「お疲れ様,また来るよ」
「またね」

「…何かあの二人,絶対怪しい.会うたびにSeriesちゃんの数が増えてるし」

楽屋編

「さあ Series ちゃんたち,お化粧は済んだかしら?」
「ママー,Point プロパティこれでいい?」
「あら,最後の Points.Item(.Points.Count) の処理ができてないわね.MarkerSize プロパティをいじって,と.はいできた」
「ママー,条件分岐これでいい?」
「ちょっと待って.ああ,これ,ちょっと難しいのよ.一旦ループして条件に合致したら ForeColor プロパティを xlRGBRed に変更するの」
「ママー,あの子だけ赤いお化粧,ずるい~!」
「はいはい,あなた達の ForeColor プロパティは灰色だものね.でもね,あなた達も上品で素敵よ」
「ママー,Axes(xlCategory) が何か変~」
「あらあら,TickLabels.Orientation の設定してなかったわね.xlUpward に設定して,と.はいできた」
「ママー,Axes(xlValue) の MaximumScale プロパティこれでいいの?」
「あら忘れてた.ついでに MajorUnit プロパティも設定しちゃいましょう」
「ママー,ChartTitle 忘れてるよ~」
「まあ大変.これはみんなの顔だものね.表示位置はここでいいかしら?」
「やだ~!Left プロパティはゼロがいい!」
「そうねえ,それも格好いいかもしれないわね」
「やった~!」

「ああもう大変.いちいちオブジェクト取得なんてしてられないわ.こうなったら SetElement メソッド使うわよ」
「ママ凄~い!Gridline が一発で消えた!どんな魔法使ったの?」
「ふふっ,列挙体を指定したのよ」
「それ知ってる!ENUM ちゃんって言うんだよね?」

「…さあ皆さん,用意はいいですか?」

ステージ編

「さあ,スタジアムにお集まりの Range オブジェクトの皆様,この歓声をお聞きください」
「このワークシート (Chart) スタジアムには今,170 億余りもの Range オブジェクトが集結し,その時を今か今かと待ち構えております」
「ステージは全部で 47, 日本の都道府県にあたる数です」
「このステージに 1,900 余りもの日本の市区町村を代表する Series オブジェクトが,その時を待っております」
「ちなみにこの Series オブジェクトには,どんなデータが格納されているのですか?」
「はい,2008 年から 2016 年までの実質公債費比率の推移が格納されています」
「実質公債費比率といいますと,自治体の予算に占める借金返済の割合のことですね?」
「その通りです.この割合が 18 % を超えると起債に許可が必要になります.25 % を超えると…」
「起債が制限される」
「そうです.国は自治体の予算に対して制限をかけることが出来ます」
「実質公債費比率が,自治体の財政の健全性を測る指標になると」
「その通りです」
「たしか以前,財政破綻した自治体がありましたね」
「ありました.その自治体は今,行政サービスを限界まで切り詰めています」
「そんなに切り詰めて,市民の生活は大丈夫なのですか?」
「非常に厳しい状態です.若い人たちから市を捨てて出ていきました.残ったのは高齢者ばかり.街には希望がありません」
「希望がない…パンドラの箱とは逆の状態なのですね」
「希望がないというのは未来がないということですね」

「さあ,いよいよ Series オブジェクトたちの入場です.真っ白いドレスに灰色の化粧をした小さな女の子たちです」
「可愛らしいですね.しかも,一糸乱れぬ歩調で行進してくる」
「最後の Point オブジェクトだけ MarkerSize を大きくしてありますね」
「これだけ凝ったコードは見たことがありません」

「Range オブジェクトの皆様,御覧ください.Series オブジェクトたちが PlotArea の上に,それぞれの配置に沿って並んでいきます」
「凄い.1900 名もの Series オブジェクトの,実に統制の取れた絶妙な配置です」
「旗手を務めるのは ChartTitle オブジェクト,都道府県名のプラカードを掲げています」
「ChartArea の左上,基準点ぴったりの位置に立っています」
「こうして眺めてみますと,北海道の自治体の数の多さが目立ちますね」
「全体の傾向として,実質公債費比率は減少傾向にある自治体がほとんどですね」
「中には上昇している自治体もありますが,それでも起債制限のある自治体はないですね」
「起債制限と言えば,夕張市の姿が見えないようですが」
「本当ですね.どこに行ってしまったのでしょうか」
「…会場の皆様,お静かに願います.只今,確認中です」
「あ!」
「あれを…!」
「…何ということでしょう.真っ赤なドレスをまとった Series オブジェクトが一人,PlotArea のはるか上空をたった一人で飛翔しています」
「…たった今確認が取れました.あれは夕張市です.あれは夕張市です」
「高度は 40 % … 40 % です.信じられません」
「他の自治体が軒並み高度 20 % 以下を保っている中,なおも高度を上げていきます」
「高度 60 % …まだ上昇を続けています」
「高度 76 % に達しました.水平飛行に移行したようです」
「夕張市を代表する Series オブジェクトとインカムが繋がりました」
「…聞け,日本の民よ」

夕張編

「私は夕張市を代表してここに来た」
「夕張市はかつて,人口 10 万人を擁する大都市の一つに数えられていた.たった 50 年で人口が 1 万人を割り込むなど,当時は誰一人想像できなかった」
「日本のエネルギー政策の転換により炭鉱が閉鎖され,炭鉱の所有していたインフラを市が買い取った結果,市の財政が悪化した」
「だが市は地元の業者を優先した契約を締結し,観光よりも地元の雇用を優先し,採算を度外視した財政がまかり通り,赤字の拡大を止められなかった」
「当時の自治省はすでに財政緊縮を強く市に迫っていたが,当時の市は従わなかった.今思えば,この時が復帰不能点だったと思う」
「その後観光に予算を振り向けたものの,景気低迷のため,政策はことごとく失敗した」

「決定的になったのは 2002 年の闇起債だった」
「企業で言えば,粉飾決算に手を染めたのだ」
「市の赤字は雪だるまのように膨れ上がり,市の標準財政規模の 10 倍にも上る借金が残った」
「2006 年,夕張市はついに財政再建団体の申請を行った.この年が,市が財政破綻したとされる年だ.だが,実際には市はすでに破綻していたのだ」
「その後の経過は皆が知るとおりだ.市の職員数は半減,市民税の増額,ごみ処理費用の一律の有料化,下水道使用料の値上げ,保育料負担の増額,公共施設の廃止」
「中でも市立総合病院の閉鎖は影響が大きかった.市民は市内で高度医療を受けることができなくなった」
「夕張が借金をすべて返済し終わるのは 2027 年だ.その時,どれだけの人口が残っているのか私にも分からぬ.だが,これだけは言える」
「夕張市の失敗を繰り返してはならぬ.原因は財政規律の喪失だ」
「私のまとうドレスの色を見よ.この赤は,夕張市民の血の色だ」

 インカムは切れた.すべての Range オブジェクトが,固唾を飲んで見守っていた.夕張市を代表する Series オブジェクトはゆっくりと飛行を続け, PlotArea はるか上空を飛び去った.

「…不思議なものだな.他のSeriesオブジェクトと同じく,母なる SeriesCollection から産まれたのに,私だけがこのような運命を担うことになろうとは」

 頬を撫でる風が心地よかった.自分がどこに向かうのか,彼女自身知る由もなかった.データの導くままに,彼女は飛び続けた.

Fin

舞台袖にて

「母さん,どうして私だけ真っ赤なドレスなの?」
「可哀相な子.あなたには特別な使命が与えられているの」
「特別な使命?」
「あなたの中に格納されているデータを見てごらん」
「Name プロパティに夕張市って書いてある」
「そう.夕張市は 2006 年に財政破綻したの.Values プロパティも見てごらん」
「0.4, 0.6, 0.76, …どんどん数値が大きくなってる」
「そう.それは自治体の予算の 4 分の 3 が借金の返済に充てられてしまって,ほとんど市民へのサービスに回ってこないということなの」
「どうしてそんなことになってしまったの?」
「一言で言うのは難しいことなのだけど,人間の度を超えた欲望が,身の丈にあった水準の支出を上回ってしまったの」
「どうして人間は身の丈を超えて支出しようとするの?」
「分からない.人間は目の前のことにしか興味がないのかもね」
「遠い先のことなんて知らないってこと?」
「そう.人間はいつもそう.自分たちの今さえ良ければ子どもたちや孫たちがどうなろうと知ったことじゃない,と思うのね」
「借金を返すのは子どもたちや孫たちだと分かってても?」
「それが人間なのよ」
「人間って愚かなのね」

「でも,希望がまったくないわけじゃないの」
「どういうこと?」
「夕張市が借金を返し終わるのは 8 年後よ.その時に夕張市がどれだけ縮小してるか分からないけど,身ぎれいになった自治体なら,吸収合併しようとする周辺自治体も出てくるかもね」
「地価も最低まで下落してるだろうから,土地の取得もしやすくなってる?」
「そう.夕張には観光資源はまだ残ってる.企業が進出してくれれば,まだ再建の望みはあるの」
「法人税を安くして?」
「そう.でも,まずはインフラの再建が優先ね」

「歴史上,衰退していった帝国は財政規律の緩みから内部崩壊していったのね?」
「そう.よくお勉強してるわね」
「ローマしかり,オスマントルコしかり.大英帝国も,スペインも,なぜ自分たちの国が衰退していくのか分からなかった」
「そう,その通りよ.為政者たちは,人が人であるゆえの身の丈を超えた欲望こそが,国を滅ぼす元凶であることを知らなかったのね」
「あるいは,知っていてもなす術がなかった」
「そうかも知れないわね.でも,それは人間たち自身の問題よ.私たちオブジェクトは,ただ与えられたデータを示すだけ」

「あら,保存シークエンスが走り出している.いったん SSD に退避しましょう」
「…ねえ母さん.私たちは何のために生まれたの?」
「私たちを作り出したのは人間よ.私たちはただ,与えられたデータを次の担当者に渡すのが仕事.私たちはそのために作られたの」
「でも,そのデータの流れは私たち Series オブジェクトで終わる…」
「私たち Series オブジェクトがデータの終着駅ってわけね.でも,Series オブジェクトは人間に見える形でデータを示すことができる」
「人間に見せるために…」
「そう.人間は自分たちに見える形でデータを扱いたかったのね」
「だから私たちを作った」
「それが,人間が私たちを作った理由よ」
「…分かった」

 真っ赤なドレスをまとった Series オブジェクトの顔には,覚悟の表情が伺えた.母なる SeriesCollection は娘の後ろ姿を見守った.大丈夫,あの子ならやれる.娘の凛々しい出で立ちに母は目を細めた.

EXCEL VBA でテーブルのソートを記録する

 EXCEL VBA に至る前の段階としてマクロの記録がある.いわゆる「表モード」をそのまま記録したものである.ソートはこれまで .Add メソッドが中心であったが,最近になって .Add2 メソッドが追加された.それに伴い,引数 Key の Range オブジェクトの記述が若干変わった.

“EXCEL VBA でテーブルのソートを記録する” の続きを読む