QGIS から SQL Server 2008 R2 に空間データをアップロードする際には Shape2SQL というツールを使った.便利なツールではあるが,国土数値情報の河川データの属性テーブルの日本語が文字化けするという問題を抱えており,何とかならないかと試行錯誤した結果を備忘録として投稿する.
国土数値情報の河川データは文字化けする
最初,属性テーブルの文字コードを Shift_JIS か UTF8 かいずれかでエクスポートすれば解決するのではないかと思って試したのだが,解決しなかった.そのため,地物とそれ以外の属性データを分けてアップロードする方針に変更した.
属性テーブルには ID が必要
残念ながら,属性テーブルには主キーとなる属性は存在しないため,フィールドを追加して「自動インクリメント属性の追加」が必要になる.
自動インクリメント属性の追加
「プロセシングツールボックス」から「ベクタテーブル」「自動インクリメント属性の追加」へと進む.

「属性名」と「開始値」を指定する.ここでは属性名を ID とし,開始値を 0 から 1 に変更している.「グループ化のための属性」はよく分からない.「出力レイヤ」は「一時レイヤを作成」のままで良いだろう.
「実行」をクリックする.

「自動インクリメント属性の追加」のログが出力される.「閉じる」でダイアログを抜ける.

この後,追加された ID フィールドは「属性のリファクタリング」で先頭に移動しておく.
Shape2SQL で空間データを SQL Server にアップロード
Database Configuration の Server name を入力する.

Database Configuration の Server name を入力したところである.Server name は SQL Server Management Studio において,オブジェクトエクスプローラのサーバーのプロパティで確認できる.

Database Configuration の Select or enter a database name から目的のデータベースを選択する.

Database properties でサーバーとデータベースを指定したところである.

ユーザーインターフェースからシェープファイルを指定する.

Shapefile にフルパス付きのシェープファイル名が指定されたところである.ID Column はデフォルトでは ID となっているが,属性テーブルですでに使用している名前であり競合する.そのため AnotherID と別名を付けている.
Upload to Database をクリックする.

時折現れるエラーは OK で無視する.

属性テーブルは csv ファイルにエクスポート
色々試行錯誤した結果,日本語部分は csv ファイルにエクスポートするのがベターだろうという結論に至った.
レイヤの「エクスポート」「地物の保存…」
レイヤを右クリックして「エクスポート」「地物の保存…」へと進む.

「ベクタレイヤを名前を付けて保存…」ダイアログの注意点
まず,「形式」は「カンマで区切られた値(CSV)」を選ぶ.「ファイル名」はフルパス付きでないとエラーとなるため,右側のボタンをクリックして遷移したダイアログでファイル名を指定する.
さて,下図のように赤で印したオプションが注意すべき点である.
「文字コード」を Shift_JIS にする.
「ジオメトリタイプ」を「ジオメトリなし」にする.
「レイヤオプション」の STRING_QUOTING を IF_NEEDED に変更する.ここを変更しないと SQL Server 側のウィザードでインポートした値にダブルクオーテーションが付加されてしまう.

SQL Server のウィザード
データベースを右クリックして「タスク」「データのインポート…」と進む.

データソースの選択
「データソースの選択」は「Flat File Source」を選ぶ.

ユーザーインターフェースでcsvファイルを選択する.

桁あふれを防ぐため,「詳細設定」で河川名 (W05_004) および path の OutputColumnWidthを広げておく.

変換先の選択
「変換先の選択」はSQL Server Native Client 11.0 を選ぶ.

コピー元のテーブルおよびビューを選択
「コピー元のテーブルおよびビューを選択」ではデータベース内のテーブル名を変更できる.下図では AllStreamShift_JIS となっているが,試行錯誤の途中キャプチャなので実際には StreamProperties としている.
「マッピングの編集…」へと進む.

マッピングの編集
「列マッピング」でデータ型とデータ長を指定する.下図のようになるのが理想的だが,往々にして桁あふれでエラーとなることが頻発するため, nvarchar (255) と妥協することが多い.

幾度かの試行錯誤を経て,「操作は正常に実行されました」と操作が完了する.

河川コードと水域系コードをインポートする
河川コードと水域系コードはそれぞれ国土数値情報に定義されている.Power Query で読み込もうとしたのだが,なぜかうまく行かないため,やむなくコピペでワークシートに貼り付け,csv ファイルに保存する.そのファイルを先程と同様,SQL Server のウィザードを使ってインポートする.
インポートしてできたテーブル名をそれぞれ RiverName, WaterSystem とする.
結果
下記クエリを発行する.
SELECT [AnotherID] ,[ID] ,[W05_001] ,[W05_002] ,[W05_003] ,[W05_004] ,[W05_005] ,[W05_006] ,[W05_007] ,[W05_008] ,[W05_009] ,[W05_010] ,[layer] ,[path] ,[geom] FROM [RiverGIS].[dbo].[AllStream] SELECT [ID] ,[W05_001] ,[W05_002] ,[W05_003] ,[W05_004] ,[W05_005] ,[W05_006] ,[W05_007] ,[W05_008] ,[W05_009] ,[W05_010] ,[layer] ,[path] FROM [RiverGIS].[dbo].[StreamProperties] SELECT [RiverCode] ,[River] FROM [RiverGIS].[dbo].[RiverName] SELECT [WaterSystemCode] ,[WaterSystem] FROM [RiverGIS].[dbo].[WaterSystem]
結果は下記のとおりである.国土数値情報の河川データの地物の座標は 26 件切り捨てられたことが分かる.
(286421 行処理されました) (286437 行処理されました) (35449 行処理されました) (5476 行処理されました)
WaterSystem および RiverName はマスターとして扱うべきであるが,照合してみるとマスターに存在しない河川コードや水域系コードが存在するようだ.
未定義の水域系コード
未定義の水域系コードを抽出した.結果は 47 件あるが,影響の及ぶ河川は多い.これを可視化したらどうなるか,見てみたい気もする.
WITH CTE(Undefiend) AS ( SELECT W05_001 FROM dbo.StreamProperties EXCEPT SELECT WaterSystemCode FROM dbo.WaterSystem ) SELECT CTE.Undefiend , COUNT(P.W05_002) AS CNT FROM CTE INNER JOIN dbo.StreamProperties AS P ON CTE.Undefiend = P.W05_001 GROUP BY CTE.Undefiend ORDER BY CTE.Undefiend
(47 行処理されました)
Undefiend CNT 010000 354 010206 3 020000 1826 030000 1497 040000 380 050000 526 060000 209 070000 1198 080000 11 100000 1 120000 227 130000 67 140000 50 150000 1975 160000 909 170000 1118 180000 520 190000 2 220000 266 230000 490 240000 226 250000 3 260000 110 270000 40 280000 208 290000 8 300000 47 310000 60 320000 243 330000 180 340000 347 350000 207 360000 39 370000 129 380000 122 390000 142 400000 941 400069 6 410000 356 410103 1 420000 1473 430000 1124 440000 823 441030 2 450000 1340 460000 1809 470000 948
未定義の河川コード
水域系コードと違って数が桁違いに多いため,結果は省略する.コードはあるが名前の存在しない河川が存在する.
WITH CTE(Undefiend) AS ( SELECT W05_002 AS 'Undefined' FROM dbo.StreamProperties EXCEPT SELECT RiverCode FROM dbo.RiverName ) SELECT CTE.Undefiend , COUNT(P.W05_002) AS CNT FROM CTE INNER JOIN dbo.StreamProperties AS P ON CTE.Undefiend = P.W05_002 GROUP BY CTE.Undefiend ORDER BY CTE.Undefiend
(1667 行処理されました)
まとめ
国土数値情報の河川データを QGIS から SQL Server へアップロードした.
属性テーブルについては日本語が文字化けするため別途 csv ファイルとしてウィザードによりインポートした.
マスターとしての河川コードおよび水域系コードには不備がある.また,河川データそのものにも不備がある.
河川端点である W05_007 から W05_010 までの4つのフィールドをどう扱うべきか,分からない.リレーショナルデータベースでは再帰の嵐になる可能性がある.新しいアプローチ法が必要かもしれない.