🦛

SQL ServerのINSERTスクリプトをどうにかしてPostgreSQLに投入するメモ

2021/08/11に公開

要件

SQL Server から PostgreSQL に移行するために、SQL Server Management Studio でスクリプト化した SQL をどうにかして PostgreSQL に流したい。

前提

  • テーブル定義は手動で変換して、既にテーブル自体は作成済みの状態
  • Windows 上の SSMS で出力した SQL ファイルを Linux ホストに持ってきた上で実行

変換

結論から行くと、以下のコマンドを使用した。

各行の意図は後述

# コピペしても動かないです。1行にまとめてください。

nkf -Lu dbo.example.Table.sql
| tail -n +5
| head -n 3      # この行はテスト用!
| sed -e 's/$/;/'
| sed -e 's/\[dbo\]\.//'
| sed -e 's/\[//g' -e 's/\]//g'
| sed -e 's/DateTime/Timestamp/g'
| sed -e 's/^GO//g'
| sed -e 's/^INSERT/INSERT INTO/g'
| head -n -1
> sql.sql

後半の sed -e を連打しているところは、ひとつの sed -e 's/hoge/fuga/ -e 's/bar/baz/'` の形にまとめることが出来ます。まとめた方が恐らく早いですが説明しにくくなるのであえてわけてあります。

各行の意図

nkf

改行コードの変換。出力元が Windows なので改行コードが CRLF になっているので LF に。

改行コードが違うと sed がまともに動かなかったりしてつらいです。

`nkf -g dbo.example.table.sql
UTF-16

なのにも関わらず、処理後に ASCII になっているのは問題になるのか悩ましい。

tail

先頭の SQL Server 用の指示をスキップさせている。

テスト用なので本番では外す。 tail -n 10 にしてもよいが、ファイルを全部読んでしまうので遅くなる。

sed (1)

INSERT 文の末尾に ; がついていないので付ける

sed (2)

テーブル名が、 [dbo].[example] となっているので、[dbo]. を削除

sed (3)

前段の置換で、テーブル名が、 [example] となっているので、[] を削除

sed (4)

SQL Server の DateTime 型は PostgreSQL では Timestamp 型にマップすることにしたので置換。

CAST(N'2017-01-01T12:34:56.789' As Timestamp) は PostgreSQL でもそのまま通る。

sed (5)

GO は不要なので削除。空行が残りますが問題ありません。

sed (6)

SQL Server では INSERT テーブル名 が通るが、PostgreSQL では INSERT INTO テーブル名 なので INTO を補う

head

末尾に SET IDENTIFY example OFF; という行が含まれるのでそこを削除。

リダイレクト

説明不要だけど、ファイルに吐かせる

蛇足

作成した SQL ファイルは、 psql 内で \i ファイル名 とすることで実行できる。

なお、トランザクションが設定されてないので、自動 commit されることに注意。

失敗したら TRUNCATE TABLE でテーブルをクリアしてから実行していたので、特にそのあたりはケアしていません。

件数が多い場合は、\i sqlfile.sql を実行する前に begin transaction しておいた方が早いかもしれません。

※ 多分、INSERT 一回ごとに COMMIT が暗黙でかかるはずなので

その場合、進捗が分からないとつらいので、GOcommit; begin transaction; に置換すると良いかもしれません。

(100 行に 1 度挟まれています。)

あと、件数の確認は確実に行ってください。それほど多くのパターンでテストしていないので行が欠けているかもしれません。(特に、先頭・末尾)

Discussion