ALTER文を使ったテーブルにselect insert intoする際の落とし穴

概要

SQL Serverで、ALTER文使ったテーブルにデータ移行用のinsert into文にカラムをつけないで作ったらひどいめに遭いました。
insert into文にはカラムをつけましょう。(結論)
あとselectの順番もきちんと確認しましょう。

起きたこと

下記のCreate文で作られたTEMPテーブルがあったとします。
IDとNOTEのあるテーブルです。

CREATE TABLE HOGE_MASTER_TEMP (
  HOGE_ID tinyint not null
  , FUGA_NOTE NVARCHAR(10) not null
);

中のデータは下記とします。

----------------------------
| HOGE_ID | FUGA_NOTE |
----------------------------
|         1 | 002           |
----------------------------
|         2 | 004           |
----------------------------

これを下記Create文で作られた正式なHOGE_MASTERテーブルに移すとします。

CREATE TABLE HOGE_MASTER (
  HOGE_ID tinyint not null
  , FUGA_NOTE NVARCHAR(10) not null
);

移行用に下記のSQLを用意します。
これで一見、HOGE_MASTER_TEMPからselectしたデータがHOGE_MASTERにinsertされそうに見えます。
実際にローカルで作業したときはデータが投入されたのです(重要)

INSERT INTO HOGE_MASTER
SELECT
  HMT.HOGE_ID
  , HMT.FUGA_NOTE
FROM
  HOGE_MASTER_TEMP HMT

しかし、本番環境のテーブルは、度重なるALTER文によりFUGA_NOTEとHOGE_IDが入れ替わり、下記のようなカラムになっていたとします。

CREATE TABLE HOGE_MASTER (
  FUGA_NOTE NVARCHAR(10) not null
  , HOGE_ID tinyint not null -- HOGE_IDが先頭に来てない…
);

知らずに先程のSQLを流すと、HOGE_MASTERの中身はこうなります。
(HOGE_IDにもともと文字だった数値が入っている…)

----------------------------
| FUGA_NOTE | HOGE_ID |
----------------------------
| 1            |        2 |
----------------------------
| 2            |        4 |
----------------------------

どうしてこんなことに…。AS句を使えばいいのでしょうか?
残念ながら下記のようにAS句を使ったとしても同じ結果になります。

INSERT INTO HOGE_MASTER_TEMP
SELECT
  HM.HOGE_ID AS HOGE_ID
  , HM.FUGA_NOTE AS FUGA_NOTE
FROM
  HOGE_MASTER HM

どうやらAS句にHOGE_IDと書いたところでinsertするカラムがHOGE_IDになるわけではないようです。

----------------------------
| FUGA_NOTE | HOGE_ID |
----------------------------
| 1            |        2 |
----------------------------
| 2            |        4 |
----------------------------

結局どうすればいいのか?

下記のようにカラムを指定した上で、select句の順番とあっているか確認しましょう。
(ASは飾りかもしれませんが、指定しておいたほうがわかりやすいかもしれません)
本番とカラムの順番が違っててまともにTEMPからデータを復元できていなかったことにあとから気づくよりはるかにましです…。

INSERT INTO HOGE_MASTER(HOGE_ID,FUGA_NOTE) --テーブルにカラムを指定する
SELECT
  HM.HOGE_ID AS HOGE_ID --AS句、順番が優先されるので指定がないよりマシかも。なお、insert先のカラム名が違うなら書いたほうがいい
  , HM.FUGA_NOTE AS FUGA_NOTE
FROM
  HOGE_MASTER HM

これで本番のカラムの順番が入れ替わっていても無事にHOGE_MASTERのカラムにはそれぞれ正式なデータが入りました。
(HOGE_IDにtinyintのIDが入っていますね)

----------------------------
| FUGA_NOTE |  HOGE_ID|
----------------------------
|002           |         1 | 
----------------------------
|004           |         2 |
----------------------------

おわり。

SQL
スポンサーリンク
シェアする