PostgreSQL での列のデータ型変更について
PostgreSQL のテーブルである列のデータ型を変更したい場合、互換性のある列データ型への変更は次のように ALTER TABLE ALTER COLUMN で変更できます。ALTER TABLE [テーブル名] ALTER COLUMN [列名] TYPE [新しいデータ型];
しかし実際にはデータ型の変更は、データ型変更前後のデータ型間で互換性のある変更なのか、互換性のないデータ型変更なのかによって変更方法が若干異なります。
列データ型を変更するテストテーブル作成
では実際に列データ型の互換性がある場合の列データ型を変更してみます。 ここでは int 型(integer)から bigint 型に変更してみますが、これらは同じ数値データ型で 互換性があります。CREATE TABLE population (
rank int,
country text NOT NULL,
region text,
population text
);
=> \d population
Table "public.population"
Column | Type | Modifiers
------------+---------+-----------
rank | integer |
country | text | not null
region | text |
population | bigint |
またテストデータも登録しておきましょう。
テスト用に "population.csv" という CSV ファイルを用意しました。これは 2017/07/01 時点での正解の人口ランキングの上位30カ国を示すデータです。 この CSV データを COPY コマンドを使ってテーブルに登録します。日本ってこんなに上位にいるんですね!?
[population.csv]
rank,country,region,population
1,China,Asia,"1,409,517,397"
2,India,Asia,"1,339,180,127"
3,United States,Americas,"324,459,463"
4,Indonesia,Asia,"263,991,379"
5,Brazil,Americas,"209,288,278"
6,Pakistan,Asia,"197,015,955"
7,Nigeria,Africa,"190,886,311"
8,Bangladesh,Asia,"164,669,751"
9,Russia,Europe,"143,989,754"
10,Mexico,Americas,"129,163,276"
11,Japan,Asia,"127,484,450"
12,Ethiopia,Africa,"104,957,438"
13,Philippines,Asia,"104,918,090"
14,Egypt,Africa,"97,553,151"
15,Vietnam,Asia,"95,540,800"
16,Germany,Europe,"82,114,224"
17,Congo,Africa,"81,339,988"
18,Iran,Asia,"81,162,788"
19,Turkey,Asia,"80,745,020"
20,Thailand,Asia,"69,037,513"
21,United Kingdom,Europe,"66,181,585"
22,France,Europe,"64,979,548"
23,Italy,Europe,"59,359,900"
24,Tanzania,Africa,"57,310,019"
25,South Africa,Africa,"56,717,156"
26,Myanmar,Asia,"53,370,609"
27,South Korea,Asia,"50,982,212"
28,Kenya,Africa,"49,699,862"
29,Colombia,Americas,"49,065,615"
30,Spain,Europe,"46,354,321"
=> \copy population from 'population.csv' csv header
=> select * from population ;
------+----------------+----------+---------------
rank | country | region | population
------+----------------+----------+---------------
1 | China | Asia | 1,409,517,397
2 | India | Asia | 1,339,180,127
3 | United States | Americas | 324,459,463
4 | Indonesia | Asia | 263,991,379
5 | Brazil | Americas | 209,288,278
6 | Pakistan | Asia | 197,015,955
7 | Nigeria | Africa | 190,886,311
8 | Bangladesh | Asia | 164,669,751
9 | Russia | Europe | 143,989,754
10 | Mexico | Americas | 129,163,276
11 | Japan | Asia | 127,484,450
12 | Ethiopia | Africa | 104,957,438
13 | Philippines | Asia | 104,918,090
14 | Egypt | Africa | 97,553,151
15 | Vietnam | Asia | 95,540,800
16 | Germany | Europe | 82,114,224
17 | Congo | Africa | 81,339,988
18 | Iran | Asia | 81,162,788
19 | Turkey | Asia | 80,745,020
20 | Thailand | Asia | 69,037,513
21 | United Kingdom | Europe | 66,181,585
22 | France | Europe | 64,979,548
23 | Italy | Europe | 59,359,900
24 | Tanzania | Africa | 57,310,019
25 | South Africa | Africa | 56,717,156
26 | Myanmar | Asia | 53,370,609
27 | South Korea | Asia | 50,982,212
28 | Kenya | Africa | 49,699,862
29 | Colombia | Americas | 49,065,615
30 | Spain | Europe | 46,354,321
------+----------------+----------+---------------
(30 rows)
データ型を互換性のあるデータ型に変更
それでは早速テーブルの列のデータ型を互換性のあるデータ型に変更してみます。意図した通りにデータ型が int 型(integer)から bigint 型に変更されており、 もちろんデータは何も変更されずにそのまま残っています。
=> ALTER TABLE population ALTER COLUMN rank TYPE bigint;
ALTER TABLE
=> \d population
Table "public.population"
Column | Type | Modifiers
------------+--------+-----------
rank | bigint |
country | text | not null
region | text |
population | bigint |
データ型を互換性のないデータ型に変更
互換性のあるデータ型変更は問題なく変更できましたが、今度は先のテーブルの "population" 列の値にカンマ(,)が入っています。このカンマがあると集計処理がやりにくいのでカンマを全部削除し、text 型になっている列データ型を数値型 (bigint) に変更します。まず replace 関数を使ってカンマを全部削除します。
=> UPDATE population SET population = replace(population, ',', '') ;
UPDATE 30
=> SELECT * FROM population ;
rank | country | region | population
------+----------------+----------+------------
1 | China | Asia | 1409517397
2 | India | Asia | 1339180127
3 | United States | Americas | 324459463
4 | Indonesia | Asia | 263991379
5 | Brazil | Americas | 209288278
6 | Pakistan | Asia | 197015955
7 | Nigeria | Africa | 190886311
8 | Bangladesh | Asia | 164669751
9 | Russia | Europe | 143989754
10 | Mexico | Americas | 129163276
11 | Japan | Asia | 127484450
12 | Ethiopia | Africa | 104957438
13 | Philippines | Asia | 104918090
14 | Egypt | Africa | 97553151
15 | Vietnam | Asia | 95540800
16 | Germany | Europe | 82114224
17 | Congo | Africa | 81339988
18 | Iran | Asia | 81162788
19 | Turkey | Asia | 80745020
20 | Thailand | Asia | 69037513
21 | United Kingdom | Europe | 66181585
22 | France | Europe | 64979548
23 | Italy | Europe | 59359900
24 | Tanzania | Africa | 57310019
25 | South Africa | Africa | 56717156
26 | Myanmar | Asia | 53370609
27 | South Korea | Asia | 50982212
28 | Kenya | Africa | 49699862
29 | Colombia | Americas | 49065615
30 | Spain | Europe | 46354321
(30 rows)
では互換性のないデータ型変更 (text から bigint) に変更してみましょう。
=> ALTER TABLE population ALTER COLUMN population TYPE bigint; ERROR: column "population" cannot be cast to type bigint"population" 列のデータ型を bigint にキャスト(型変換)出来ないというエラーになりました。
互換性のないデータ型への変更を行うには、"USING" という命令の後に明示的にデータ型を変更 する指示を行って上げる必要があります。text 型の値を bigint に変換するには「population::bigint」と することで変換可能です。
ということで、次のようにするとデータ型が変更できます。そしてもちろんデータは何も変更されていません。
=>
ALTER TABLE population
ALTER COLUMN population
TYPE bigint USING population::bigint;
=> \d population
Table "public.population"
Column | Type | Modifiers
------------+---------+-----------
rank | integer |
country | text | not null
region | text |
population | bigint |
=> SELECT * FROM population ;
rank | country | region | population
------+----------------+----------+------------
1 | China | Asia | 1409517397
2 | India | Asia | 1339180127
3 | United States | Americas | 324459463
4 | Indonesia | Asia | 263991379
5 | Brazil | Americas | 209288278
6 | Pakistan | Asia | 197015955
7 | Nigeria | Africa | 190886311
8 | Bangladesh | Asia | 164669751
9 | Russia | Europe | 143989754
10 | Mexico | Americas | 129163276
11 | Japan | Asia | 127484450
12 | Ethiopia | Africa | 104957438
13 | Philippines | Asia | 104918090
14 | Egypt | Africa | 97553151
15 | Vietnam | Asia | 95540800
16 | Germany | Europe | 82114224
17 | Congo | Africa | 81339988
18 | Iran | Asia | 81162788
19 | Turkey | Asia | 80745020
20 | Thailand | Asia | 69037513
21 | United Kingdom | Europe | 66181585
22 | France | Europe | 64979548
23 | Italy | Europe | 59359900
24 | Tanzania | Africa | 57310019
25 | South Africa | Africa | 56717156
26 | Myanmar | Asia | 53370609
27 | South Korea | Asia | 50982212
28 | Kenya | Africa | 49699862
29 | Colombia | Americas | 49065615
30 | Spain | Europe | 46354321
(30 rows)
このようにデータ型変更前後で、データ系に互換性があるかないかによって変更方法が若干異なるということです。
