
ServiceNowのImport Setを実際に取り込むとどうなる? sys_import_set_rowとcoalesce更新を実機で確認
Import SetとTransform Mapの仕組みは分かっても、実際に取り込むと結果がどこに残るのか、2回目に同じキーで取り込むと本当に更新になるのか、という疑問は残ります。今回はcmn_location(ロケーション)に実データを流し込み、InsertとUpdateとエラー狙いの記録を1つずつ実機で追いました。3件投入して3件Insert、うち1件を同じキーで再送信してUpdateにする、というところまで実際に確認できています。
検証環境:Zurich PDI / OOTB / 2026-08-10 確認
結果を先に書きます
3件投入して、3件ともInsertされました
そのうち1件を同じ5つのキーで再送信したところ、新規作成されずUpdateになりました
必須項目を空にするなど4パターンでエラーを狙いましたが、すべて成功してしまいました。理由も分かりました

これが今回の全体像です。1つのImport Setの中に、8回ぶんの実行結果が並んでいます。上から4行が今回のA・B・Cと、Cの再送信。残り4行がこのあと説明するエラー狙いの試行です。Insertsの列とUpdatesの列を見るだけで、何件が新規で何件が更新だったかが一目で分かります。
今回やったこと:cmn_locationに実データを流す
対象はcmn_locationです。すでにOOTBで用意されている「Location」というTransform Map(imp_location→cmn_location)をそのまま使いました。coalesceキーはname・city・state・street・zipの5項目で、この5つがすべて一致したときだけ既存レコードとみなされます。countryだけはcoalesce対象外です。
投入したのは架空のデータ3件だけです。検証用ロケーションA・B・Cという名前で、都市も州も番地も全部「検証用」を付けています。実在しそうな企業名や住所は使っていません。

今回の分岐はこの図の通りです。coalesceキーが一致しなければInsert、一致すればUpdate。この2つは実際に両方とも起こせました。右側のエラー狙いは、狙った通りには動きませんでした。詳しくは後半で書きます。
投入の方法にも触れておきます。ブラウザからCSVファイルをアップロードするのではなく、ServiceNowのImport Set API(/api/now/import/imp_location)から1行ずつ送信しました。このAPIは、ステージングテーブルへの挿入とTransform Mapの実行という、CSV取込とまったく同じサーバ側の処理を通ります。データの持ち込み方が違うだけで、coalesceの判定もResultの記録先も変わりません。スクリプトや外部システムからServiceNowへデータを流すときは、このAPIを直接呼ぶ設計もよく使われます。
なぜcmn_locationを選んだかにも理由があります。以前書いたcoalesceの記事とインポートログの記事では、どちらも実データが0件だったため、「実際に取り込むとどうなるか」を検証範囲外にしていました。今回はその空白を埋めるための検証です。業務の中核テーブル(incidentやchange、cmdb_ciなど)ではなく、影響範囲が読みやすいロケーションを選んだのは、後片付けまで含めて安全に一巡させたかったからです。
1回目:3件投入して3件Insertされました
まず、A・B・Cの3件をそれぞれ別のリクエストで投入しました。結果はAPIの応答にそのまま返ってきます。3件ともstatusがinsertedで、対象のcmn_locationレコードのsys_idが割り当てられていました。

実際にcmn_locationを見ると、3件がきちんと作られています。Updatedの列を見ると、A・Bが同じ秒に近い時刻、Cだけ少し遅い時刻になっています。これは、Cをこのあと2回目の取込で更新したためです。1回目の時点では、3件とも「新しく作られただけ」の状態でした。
APIの応答には、target_table・display_value・record_link・statusといった項目が1件ずつ返ってきます。record_linkには、作られたレコードを直接取得できるURLが入っていました。取込を自動化する側の視点で見ると、この応答をそのままログに残しておけば、「どの入力行がどの本番レコードになったか」を後から追跡できます。1件ずつ画面で確認しなくても、応答を保存するだけで追跡できる、というのは実務上ありがたい作りです。
2回目:同じキーでcountryだけ変えたらUpdateになりました
ここが今回の山場です。Cと同じ5つのキー(name・city・state・street・zip)を使い、coalesce対象外のcountryだけを「検証国X」から「検証国Y」に変えて、もう一度送信しました。
結果はstatusがupdated。しかもsys_idは1回目のCとまったく同じでした。新しいレコードは作られていません。

cmn_locationのフォームを開くと、countryが実際に「検証国Y」に変わっています。他の項目(name・city・state・street・zip)はそのままです。coalesceキーが一致していれば、キー以外のフィールドが変わっても新規作成にはならず、既存レコードの該当項目だけが上書きされる、ということが実データで確認できました。
なぜcountryを変えたのか
これは偶然ではありません。今回使ったTransform Mapでcoalesce=trueなのはname・city・state・street・zipの5つで、countryだけがfalseです。つまりcountryは「突合には使わないが、値は転記される」項目です。coalesceキーそのものを変えてしまうと、それは「別の拠点」として扱われてInsertになってしまいます。同一性を保ったままUpdateを確認するには、キー以外の項目を変える必要があり、今回のマップではcountryがちょうどそれに当たりました。
実務でも同じ発想が使えます。取込先のレコードに「値は更新したいが、同一性の判定には使いたくない項目」が1つでもあれば、それをcoalesce対象外にしておく設計です。逆に、すべての項目をcoalesce対象にしてしまうとどうなるでしょうか。1文字でも表記が揺れただけで別レコード扱いになります。Updateのつもりが、延々とInsertされ続けるという事故につながります。

エラーを1件起こそうとして、4回とも失敗しました
次はエラーです。必須項目を空にするなど、4つのやり方でわざとエラーを起こそうとしました。
cityを空文字にして送信
nameを96文字のASCII文字列にして送信(想定される上限を大きく超える長さ)
cityに文字列ではなくオブジェクトを送信
cityに日本語300文字を送信
結果は、4パターンともinsertedでした。空のcityはそのまま空で登録され、長すぎる文字列は途中で自動的に切り詰められ、型の違う値は文字列に変換されて格納されました。エラーになったものは1件もありません。
どのパターンも、ServiceNow側が親切に「なんとかしてくれた」形です。空値は空値のまま受け入れ、長すぎる値は黙って削り、想定外の型は文字列に変換する。壊れたデータで処理全体が止まるより、ある意味では扱いやすい設計とも言えます。ただし、それは「エラーで気づけない」ことの裏返しでもあります。
原因はTransform Mapの1つの設定でした
なぜ空値でも通ってしまうのか。Transform Mapの設定を確認したところ、答えが見つかりました。

「Enforce mandatory fields」という項目が「No」になっています。この設定が既定値のままだと、ステージング側のテーブルで必須マークが付いている項目でも、Transformの時点では弾かれません。この記事ではこの値をあえて変更していません。共有のOOTB設定を書き換えて記事のために動かす、ということはしたくなかったからです。読み取りだけで「なぜ通ってしまうのか」の理由までは説明できるので、それで十分だと判断しました。
もし読者の環境でエラーを再現したいなら、この設定を「Yes」に切り替えたうえで同じテストをする、というのが次の一手になります。
この結果は、データ品質の観点でも見過ごせません。連携元のシステムで必須項目が空のまま出力されていても、ServiceNow側の取込設定が既定値のままだと、それをそのまま受け入れてしまいます。「取込が正常終了した」ことと「データが正しい」ことは、イコールではありません。取込を新しく設計するときは、Enforce mandatory fieldsを有効にするかどうかを、coalesceの設計と同じくらい早い段階で決めておく方がよいと感じました。
結果は3か所に残ります
ここまでの結果は、実際には3つの場所に記録されていました。
sys_import_set_row:1行ごとの顛末
1行ごとの結果が、State・Target record・Errorという形で残っています。今回は8行のうち、Insertedが7、Updatedが1、Errorは0でした。行のフォームを開くと、どのレコードが対象になったかまでリンクでたどれます。

Cを更新した行を開くと、StateがUpdatedになっていて、Target recordが元のCと同じレコードを指しています。この画面を見れば、「この1行が何をしたか」がひと目で分かります。
sys_import_set_run:実行ごとの集計
Import Setのフォームから見える集計テーブルです。1回の実行ごとに、Total・Inserts・Updates・Ignored・Skipped・Errorsの数がまとまっています。冒頭に貼った画面がこれで、8回分の実行結果がすべて並んでいました。1件ずつ数えなくても、ここを見るだけで「何件成功して何件失敗したか」が分かります。
import_logには何も残りませんでした
もう1つの記録先であるimport_logも確認しました。以前の記事では、実データが無かったため「本来はここに記録されるはず」という推測にとどめていました。今回は実データを流したので、実際に確認できます。
結果は、今回の取込に由来するログは0件でした。既存のクリーンアップメッセージだけが残っていて、今回投入した8行についての記述は見つかりません。Import Set APIからの投入では、少なくとも今回の環境と設定では、import_logに運用ログが残らないということが実測で分かりました。
この結果は、少し意外でした。import_logのテーブル定義には、取込セットや取込行へのリンク項目がちゃんと用意されています。構造上は記録できるようになっているのに、Import Set API経由の投入では実際には使われていない、ということになります。ブラウザからCSVを手動でアップロードした場合に同じログが残るのかどうかは、今回は確認していません。取込の経路によって記録先が変わる可能性がある、という点は、今後の調査課題として残しておきます。
実務で使う対応表:何を知りたいときにどこを見るか
ここまでの内容を、実務で使える形に整理しておきます。

全体の傾向をざっと知りたいならTransform Historyを開きます。1行の顛末を追いたいならsys_import_set_rowのStateが手がかりです。なぜUpdateになったのか根拠まで知りたいときは、Transform MapのField Mapsまで戻る必要があります。目的によって、開く画面はこのように変わってきます。
カットオーバー直前のリハーサル取込でも、この3段階の順番はそのまま使えます。
Transform Historyを開き、件数の桁が合っているかを確認する
Errorが出ていればsys_import_set_rowで該当行を特定する
原因がcoalesceの設定にありそうなら、最後にField Mapsまで遡って見直す
粗いところから細かいところへ順に絞り込んでいく、というのがこの3段階の考え方です。
実機で気づいたこと
空値でも通ってしまう理由を知って設計が変わった
必須項目を空にすればエラーになる、と思い込んでいました。実機ではそうなりませんでした。Transform Mapの「Enforce mandatory fields」がNoのままだと、ステージング側の必須マークは効きません。この存在を知らないと、「なぜ空データが本番に紛れ込むのか」を延々と探すことになります。取込の設計をレビューするときは、coalesceだけでなくこの設定も見るようにしたいと感じました。
リストの既定列にはStateが出ない
sys_import_set_rowの一覧画面を素の状態で開くと、既定の列は「Import set run」と「Template Import Log」だけで、肝心のStateが表示されません。

最初は「行が正しく作られていないのでは」と少し戸惑いました。実際には行はきちんと存在していて、単に一覧の既定列にStateが含まれていないだけでした。1行を開いてフォームで見るか、列を追加しないと、結果は見えてきません。取込の結果確認は、一覧をざっと眺めるより、気になる行を開く方が早いと分かりました。
countryが外れている理由が腹落ちした
以前の記事でcoalesceキーが5項目あることは知っていましたが、なぜcountryだけ外れているのかは、実際に更新テストをするまでピンと来ていませんでした。全項目をキーにしてしまうと、キー以外に変えられる値が無くなり、Updateの動作を試すことすらできません。coalesceに含めない項目を1つ残しておくことには、そういう実務上の意味もあるのだと実感しました。
CSVアップロードにこだわらなくてよいと分かった
取込の記事というと、CSVファイルをブラウザからアップロードする画面を思い浮かべがちです。今回、Import Set APIから直接データを送っても、Transform Mapの動きもcoalesceの判定も記録の残り方も、CSV取込と何も変わらないことが分かりました。定期的に届くCSVを人が手作業でアップロードする運用もあれば、外部システムからAPIで直接流し込む運用もあります。どちらも通る道筋は同じTransform Mapです。取込の設計を考えるときは、入口がCSVかAPIかよりも大事な論点があります。それは、coalesceとEnforce mandatory fieldsをどう設定するかです。
まとめ
Import Setを実際に走らせると、結果はsys_import_set_row・sys_import_set_run・import_logの3か所に分かれて残ります。coalesceキーが一致すればUpdate、一致しなければInsert。この基本の動きは、実データでもそのまま確認できました。一方で、必須項目を空にしてもエラーにならない、という想定外の結果も出ました。原因はTransform Mapの1つの設定にあり、既定値を知っておくだけで、取込の挙動をずっと正確に予想できるようになります。
「Import SetとTransform Mapの仕組みは分かったが、実際に取り込むとどうなるかまでは試していない」という状態から、今回はもう一歩踏み込みました。仕組みの理解と、実際に動かしたときの挙動は、必ずしも一致しません。今回のように件数が読める範囲であれば、本番相当のテーブルであっても、架空データで一度動かしてみる価値はあると考えています。
今回投入したデータは記事のための一時的なものなので、証跡を取ったあとにすべて削除しました。cmn_locationの件数は、投入前と削除後でぴったり一致しています。
用語
sys_import_set_row … 取込1行ごとの結果(State・Target record・Error)を持つテーブル
sys_import_set_run(Transform History) … 実行1回ごとのTotal・Inserts・Updates・Errorsの集計
Enforce mandatory fields … Transform Mapの設定項目。有効にすると必須項目の欠落でエラーになる
coalesce … 取り込む行を既存レコードに突合するキー。一致すればUpdate、なければInsert
Import Set API … CSVを介さずステージングとTransformを直接呼び出すREST API
自分の環境で確認するときのURL
自分のインスタンス名を先頭に付けると、同じ画面が開けます。
/sys_import_set_row_list.do?sysparm_query=sys_import_set=<番号>(1行ごとの結果一覧)
/sys_import_set.do?sys_id=<sys_id>(Import Setの実行履歴)
/sys_transform_map.do?sys_id=<sys_id>(Enforce mandatory fieldsなどTransform Mapの設定)
検証範囲とおことわり
ブラウザからのCSVアップロードは行っていません。Import Set API経由でステージングテーブルに投入しました。ステージング挿入とTransform実行のサーバ処理はCSV取込と同一ですが、CSVパーサーを通す体験そのものは今回の検証範囲外です。
Transform Mapの「Enforce mandatory fields」を実際にYesへ変更した場合の挙動は確認していません。今回は読み取りのみで、この設定を変えていません。
投入したのは3〜5件規模のデータです。数千〜数万件の大量取込での挙動や速度は検証範囲外です。
記事のために投入したデータ(cmn_locationのレコードとImport Set本体)は、証跡を取ったあとにすべて削除しました。削除後の件数は投入前と一致することを確認しています。検証環境に一時的にデータを投入し、確認後に削除しています。