web-dev-qa-db-ja.com

varchar列をinetに変換する

IPアドレスを含むテーブル列があります。データ型はvarchar(255)です。 inetデータタイプに切り替えたいのですが。 IP列の既存のアドレスをinetデータ型に変換する方法はありますか?試した:

ALTER TABLE request_logs ALTER COLUMN ip type inet USING ip::inet;
ALTER TABLE request_logs ALTER COLUMN ip type inet USING CAST(ip AS inet);

しかし、運が悪い。

PG::DatatypeMismatch:
ERROR:  default for column "sign_up_ip" cannot be cast automatically to type inet

すべての値は'127.0.0.1'。 Postgresのバージョンは9.6.9です。

3
user882027

ALTER TABLEステートメントは私にとってはうまくいきます。エラーメッセージは、列sign_up_ipDEFAULT値が付加されていることを示しています。これは、新しいデータ型inet。最初に列のデフォルトを削除してから、データ型を変換します。 次に、新しいデフォルトを追加します(該当する場合)。

それがと思われるとしても有効です。 マニュアル、「列のデータ型の変更」の章:

PostgreSQLは、列のデフォルト値(存在する場合)を新しい型に変換しようとするだけでなく、列に関連する制約も変換します。しかし、これらの変換は失敗するか、驚くべき結果をもたらす可能性があります。多くの場合、列の型を変更する前に列の制約を削除し、その後、適切に変更された制約を後で追加し直すのが最善です。

varcharinetの間に登録されたキャストはありません。そのため、明示的な変換を伴うUSING句を追加する必要がありました。 Postgresは、入力/出力変換を介して動作します。しかし、保存されたDEFAULT式ではそれは不可能です。

すべてを1つのDDLコマンドで実行して、同時トランザクションとの摩擦を最小限に抑えることができます(必要な場合)。

ALTER TABLE request_logs
   ALTER COLUMN sign_up_ip DROP default
 , ALTER COLUMN sign_up_ip type inet USING ip::inet
 , ALTER COLUMN sign_up_ip SET DEFAULT '192.168.1.1';  -- arbitrary example

コード例では、記号ipの代わりにactual列名sign_up_ipを使用します。 Postgres 10でテスト済み。

If列に、タイプvarcharとして無効なinet値を保持する必要がある場合でも、変換は失敗しますが、今回は次のようなもので:

ERROR:  invalid input syntax for type inet: "1234.123.123.123"

これが、1つのステートメント(または少なくとも1つのトランザクション)ですべてを実行することが望ましい理由の1つです。エラーと自動ROLLBACKの後ですべてが元の状態に戻ります。

4