レコードの sys_id を調べる方法(8通り)
ServiceNow のレコードには sys_id という32桁の識別子が必ず付いています。incident でも change_request でも、ユーザーが作ったカスタムテーブルでも同じです。ところがこの sys_id は、フォーム画面を開いただけでは表示されません。
困るのは、スクリプトを書くときと、他システムと連携するときです。GlideRecord でレコードを一意に特定するにも、外部システムとキーを突き合わせるにも、sys_id が要ります。見えない項目をどう調べるか、これが今回のテーマです。
調べる手段は1つではありません。URLを見る、右クリックメニューを使う、一覧に列を足す、この3つがまず基本です。ほかにエクスポートに含める方法と、スクリプトから取る方法があります。場面によって向き不向きがあるので、8通りをまとめて並べます。
想定読者は、ServiceNow を業務で使っていて、スクリプトや外部連携で sys_id が必要になった人です。
この記事の内容は ServiceNow の PDI(Personal Developer Instance)Zurich リリースの OOTB(初期設定)で確認しています。実環境では権限やカスタマイズにより結果が変わります。
この記事で分かること
sys_id がどんな項目か(32桁の16進文字列である理由、対象テーブルの範囲)
画面から調べる4通りの方法(URL / 右クリック3種)とそれぞれに必要な権限
一覧・エクスポートでまとめて調べる2通りの方法
スクリプトから取得する2通りの方法(クライアント / サーバー)と、遠回りな書き方との違い
用途別にどの方法を選べばいいか、よくあるつまずき5つ
そもそも sys_id とは
まずは定義からです。sys_id は、ServiceNow のレコードに自動で振られる32桁の16進文字列です。テーブルを作ると、そのテーブルにも sys_id 列が同時に用意されます。公式ドキュメントのUnique record identifier (sys_id)でも、すべてのレコードの主キーとして扱われる項目だと説明されています。
実測してみます。実際に sys_dictionary を element=sys_id で絞ると6,008件がヒットしました。テーブル総数(sys_db_object)は6,317件なので、6,008件は全体の約95%にあたります。ほぼ全てのテーブルに sys_id 列があることになります。

incident の number(INC0010001のような番号)は人が読むための項目です。レコードを内部的に一意に特定しているのは number ではなく sys_id のほうになります。参照フィールド(Reference)が別テーブルのレコードを指すときも、実際に格納されているのは相手先の sys_id です。この違いはReference field typeのドキュメントで扱われていて、詳しい仕組みは別の記事でも取り上げています。
なぜ32桁の16進文字列なのか
sys_id が使う文字は 0〜9 と a〜f の16種類だけです。1文字が16通りを表す16進数で、それが32桁並ぶので、理論上の組み合わせは16の32乗、ビット数にすると128ビットという計算になります。この規模の空間からランダムに値を選ぶ方式は、一般に GUID(Globally Unique Identifier)と呼ばれる設計です。形式としては、業界標準であるUUID(Universally Unique Identifier)からハイフンを取り除いたものとほぼ同じだと考えられます。
連番の数値を主キーにしないのには理由があります。連番だと、複数の環境で同時に作られたレコードのIDが衝突します。PDIで作ったテスト用のレコードを本番に持っていく場合も、同じ番号が本番側に既に存在していれば、上書きや不整合が起きかねません。GUID方式なら、どの環境で・いつ作られたレコードでも、同じ値が偶然重なる可能性は無視できるほど小さくなります。更新セットやデータのインポート・エクスポートを前提にした設計だと考えられます。
sys_id とレコードの作成順は無関係
sys_id の文字列を見て、作成が早いか遅いかを判断したくなることがあります。しかし GUID はランダムに近い方式で生成されるため、文字列の並びと作成日時には関係がありません。作成日時を知りたいときは、sys_created_on フィールドを見る必要があります。この点は後半のFAQでも触れます。
画面から調べる4通り
フォームを開いた状態から、追加の設定なしに確認できる方法が4つあります。URLを読む方法と、右クリックメニューを使う3つの方法です。
方法1:URLを見る
最も手軽な方法です。レコードのフォームを開くと、ブラウザのアドレスバーに sys_id=から始まるパラメータが並びます。Classic UI の場合は incident.do?sys_id=xxxxxxxx... という形です。すでに画面を開いているなら、追加の操作なしにこの方法で確認できます。

新規作成直後の画面はまだ sys_id=-1 のような仮の値になっていることがあります。保存してから画面を開き直すと、正しい sys_id が表示されます。
逆に、sys_id さえ分かっていれば incident.do?sys_id=xxxxxxxx... のようにURLへ直接指定して、そのレコードを一発で開けます。一覧から探す手間を省きたいとき、この開き方はスクリプトの実行結果や調査メモに sys_id を控えておくだけで使えるので便利です。
方法2:右クリック > Copy sys_id
IDだけを最短で得られます。フォームのヘッダ部分(グレーの帯)を右クリックすると、コンテキストメニューが出ます。ここに Copy sys_id という項目があり、クリックすると32桁の文字列だけがクリップボードにコピーされる仕組みです。URLから切り出す手間がいらないぶん、スクリプトに貼り付ける用途に向いています。

この項目が定義されている sys_ui_context_menu テーブルを実際に見ると、Copy sys_id の条件式には gs.hasRightsTo("ui/context_menu.copy_sysid/read", null) という権限チェックが入っていました。管理者ロールを持たないユーザーには、そもそもメニュー自体が表示されません。
方法3:右クリック > Copy URL
共有向けの方法です。同じ右クリックメニューには Copy URL もあります。クリックすると、sys_id を含んだURLをまるごとコピーする機能です。ID単体ではなく、そのレコードへのリンクを誰かに送りたいときに使います。
Copy sys_id とは対照的に、Copy URL to Clipboard の条件式は !RP.isPortal() だけでした。ポータル画面でなければ表示するという制約しかなく、特別な権限チェックはありません。管理者以外のユーザーでも使える手段だという点が、Copy sys_id との実務上の違いになります。
方法4:右クリック > Show XML
全項目を一度に見られます。右クリックメニューの Show XML を選ぶと、そのレコードをXML形式で表示した画面が開きます。sys_id はもちろん、フォームに出ていない項目まで含めて、すべての値をまとめて確認できるのが特徴です。sys_created_by や sys_mod_count のような、通常はフォームに置かれないシステム項目も同時に見えるため、値の食い違いを調べるときに重宝します。XMLの読み方そのものは別の記事で扱っています。

Show XML の条件式も Copy sys_id と同じく gs.hasRightsTo("ui/context_menu.show_xml/read", null) という権限チェックが入っています。この2つは対になった機能で、一般ユーザーの画面には出てこない設計です。
まとめて調べる2通り
ここからは、複数件をまとめて扱いたい場面に向いた方法を2つ紹介します。
方法5:一覧に sys_id 列を追加する
一覧なら複数件を一度に扱えます。複数件をまとめて調べたいときは、一覧画面に sys_id 列を足します。列見出しを右クリックし、List Layout(Configure > List Layout)から設定する操作です。sys_id を選択済みの列に移すと、一覧にそのまま反映されます。列を足したのに一覧に出てこないときは、/cache.do でキャッシュを落とすと直ることがあります。

設定は個人単位です。一覧の設定は sys_ui_list というテーブルに保存されます。ここで加えた列は自分のログインユーザーに対する個人設定として残り、他のユーザーの画面には影響しません。全ユーザー向けの標準列を変えたい場合は、管理者権限で別の設定手順を踏む必要があります。この使い分けは公式のPersonal listsとConfigure the list layoutのドキュメントで説明されています。
方法6:エクスポートに含める
大量データはエクスポートが向きます。一覧をエクスポートするとき、URLに sysparm_default_export_fields=all を付けると、通常は一覧に出ていない列まで含めて出力されます。実際にこの方法でエクスポートしたファイルに sys_id が含まれることを確認しました。

通常のエクスポート(CSV・Excel・XMLのいずれも)は、一覧に表示している列だけを書き出す仕様です。sys_id を一覧に足していなければ、エクスポート結果にも含まれません。業務担当者が読みやすいレポートになるよう、内部識別子であるsys_idをあえて含めない設計になっていると考えられます。sysparm_default_export_fields=all は、この列指定を無視して全項目を出す特別な指定です。方法5との使い分けも、この違いを知っておけばはっきりします。エクスポート機能そのものの使い分けは、公式のExport list dataやExport setsの仕組みとあわせて別の記事で扱っています。
スクリプトから取得する2通り
ここからは、スクリプトの中で sys_id を扱う場面向けの方法です。クライアント側とサーバー側で書き方が変わります。
方法7:クライアントスクリプトから
画面操作を介さない方法です。フォーム上で動くクライアントスクリプトでは、g_form.getUniqueValue() を呼ぶと、いま開いているレコードの sys_id が返ります。Onload や Onchange のスクリプトの中で、そのレコード自身のIDが要るときに使います。
var id = g_form.getUniqueValue();g_form.getValue('sys_id') という書き方を試したくなりますが、sys_id はフォームの通常項目として扱われていないため、この呼び方では値が返らないことがあります。sys_id を取るときは getUniqueValue() 専用のメソッドを使う、と覚えておくのが安全です。公式のGlideForm (g_form) - Clientにも、フォーム操作全般のAPIがまとまっています。
新規作成でまだ保存していないフォームでは、getUniqueValue() が仮の値を返すことがあります。方法1のURLと同じく、保存後に確定した値を使う前提で扱う必要があります。
方法8:サーバースクリプトから
サーバー側でも発想は同じです。サーバー側では2通りの書き方があります。Business Rule のように current というGlideRecordが渡される場面では、current.getValue('sys_id') で取れます。自分で GlideRecord を作って検索した場合は、gr.getUniqueValue() が同じ値を返す書き方です。どちらの書き方でも、返り値は文字列としての sys_id になります。
var id1 = current.getValue('sys_id');
var id2 = gr.getUniqueValue();gr.sys_id のようにドット・ウォークで直接参照する書き方も動きます。ただし返ってくるのは文字列そのものではなく、GlideElement というオブジェクトです。比較や結合の際に想定外の挙動を招くことがあります。公式のGlideRecord - Globalでも、getUniqueValue() の利用が案内されています。GlideRecord - Scopedのリファレンスも同様です。Business Rule だけでなく、Script Include や Scheduled Script Execution でも同じ書き方が使えます。Flow Designer のスクリプトステップでも、通用する範囲です。
用途別にどれを使うか
場面ごとに向いている方法と、必要な権限の目安を整理すると、次のようになります。

軸は権限の有無です。権限の面で見ると、Copy sys_id と Show XML だけが管理者ロール相当を必要とし、それ以外の6通りは一般ユーザーでも扱えます。管理者権限を持たない現場担当者に調べ方を案内する場合は、URLを見る方法か、一覧に列を足す方法をまず勧めるのが現実的です。
つまずきやすい点
コピーミスに気づきにくい
見落としがちな注意点です。sys_id は32桁の文字列で、途中に区切りがありません。URLから手作業でドラッグ選択すると、末尾の1文字だけ選び漏れる、あるいは前後の記号を巻き込む、といったミスが起きやすくなります。GlideRecordの検索条件に貼り付けた結果、該当0件で悩むケースの多くは、この選択ミスが原因です。可能な限り Copy sys_id のように、値だけを丸ごとコピーする方法を使うと事故を防げます。
Now Experience・ワークスペースでは右クリックメニューが出ない
UIによって挙動が変わります。右クリックメニューは Classic UI(UI16)の機能です。Next Experience のワークスペースでは、フォームヘッダを右クリックしても同じメニューは出ません。実際にコンテキストメニューを定義している sys_ui_context_menu を数えると86件でした。ただしこれは Classic UI 向けの定義で、ワークスペースの右クリック挙動とは別の仕組みです。ワークスペース中心の環境では、URLから読み取る方法か、スクリプトから取得する方法が実質的な代替手段になります。
参照フィールドと sys_id を混同する
見た目と実体は別物です。参照フィールドは名前が表示されますが、格納されているのは参照先レコードの sys_id です。ドット・ウォーク(current.caller_id.nameのような書き方)で取れるのは相手先の項目の値であり、sys_id そのものではありません。sys_id が欲しいときは、参照項目を文字列として直接読むか、getRefRecord() で相手先のGlideRecordを取得してから getUniqueValue() を呼ぶような書き方が必要です。この違いは別の記事で扱っています。
sys_id は作り直すと変わる
IDは固定ではありません。sys_id はレコードを作り直すと変わります。同じ内容に見えても、削除して作り直せば別のIDが振られる仕様です。他システムとの突き合わせキーとして sys_id を使う場合、移行やクローンの前後でIDが変わらないかどうか、事前に確認しておく必要があります。update setやデータのインポートで新規作成として扱われた場合、旧環境と新環境で sys_id が一致しない可能性も考えられます。
よくある質問
Q1. 同じ sys_id が別のテーブルに存在することはありますか
答えは明確です。生成方式がGUIDのため、通常は起こりません。異なるテーブルであっても、値が重なる可能性は設計上ごくわずかです。ただし、CSVインポートなどでsys_idを含んだデータを取り込む運用をしている場合は、意図せず既存の値と衝突しないか事前に確認したほうが安全です。
Q2. sys_id の並び順はレコードの作成順と一致しますか
一致するとは限りません。GUIDはランダムに近い方式で生成されるため、文字列としての大小と作成日時には関係がありません。作成順を知りたいときは sys_created_on を使ってください。
Q3. sys_id をキーにレコードを直接開くにはどうすればいいですか
方法は2つあります。画面であれば、方法1で触れたとおり テーブル名.do?sys_id=xxxxxxxx... のURLを直接開くだけです。スクリプトからであれば、GlideRecordの get(sys_id) メソッドを使うと、その1件だけを直接取得できます。一覧の絞り込み条件に sysparm_query=sys_id=xxxxxxxx... と書く方法も同様に使えます。
Q4. 参照フィールドをそのまま比較すれば sys_id の比較になりますか
なりますが注意が必要です。if (current.caller_id == "xxxxxxxx...") のような比較はGlideElementと文字列の比較になり、多くの場合は意図通りに動きます。ただし確実性を優先するなら、current.getValue('caller_id') のように明示的に文字列として取り出してから比較するほうが、意図が伝わりやすいコードになります。値が一致しない不具合を後から調査するとき、比較方法が統一されているほうが原因を切り分けやすいでしょう。
Q5. Copy sys_id や Show XML が右クリックメニューに出ないときは何を確認すればいいですか
権限の確認が先です。方法2・方法4で触れたとおり、この2つには gs.hasRightsTo によるUI権限チェックが入っています。メニュー自体が出ない場合は、ロールを確認してもらうのが先です。それでも解決しない場合は、Classic UI の画面を開いているか(ワークスペースではないか)もあわせて確認してください。
まとめ
sys_id を調べる方法は、画面から取るか、まとめて取るか、スクリプトから取るかで選び方が変わります。

選び方の軸は権限です。右クリックメニューはClassic UI限定で、しかもCopy sys_idとShow XMLは管理者ロール相当が要るという制約があります。ワークスペース中心の環境や、管理者権限を持たないユーザーに案内する場面では、URLとスクリプトからの取得が主な手段になります。8通りのうちどれを選ぶにしても、sys_idがGUIDである以上、文字列を正確にコピーすることだけは共通して気をつけたいところです。
用語
sys_id … レコードごとに自動採番される32桁の16進文字列。テーブルの主キー
GUID(Globally Unique Identifier) … 広い空間からランダムに近い方式で値を選び、重複をほぼ避ける識別子の設計方式
sys_dictionary … テーブルの列定義を格納するテーブル。element列にsys_idを含む列名が入る
sys_ui_context_menu … フォームや一覧の右クリックメニューの定義を格納するテーブル
sys_ui_list … 一覧の列構成(List Layout)を格納するテーブル
GlideElement … GlideRecordのフィールドをドット・ウォークで参照したときに返るオブジェクト。文字列そのものではない
getUniqueValue() … GlideRecord・GlideFormの双方に用意された、sys_idを文字列として返す専用メソッド
自分の環境で確認するときのURL
/incident.do?sys_id=...(フォームを開いたときのURL)
/incident.do?XML&sysparm_query=number=INC0000002(Show XMLと同じ内容をURLで取得)
/sys_dictionary_list.do?sysparm_query=element=sys_id(sys_id列を持つテーブルの一覧)
/sys_ui_list_list.do?sysparm_query=name=incident(一覧の列定義)
/incident_list.do?XML&sysparm_default_export_fields=all&sysparm_record_count=1(非表示列を含むエクスポート)
/sys_ui_context_menu_list.do(右クリックメニューの定義一覧)
検証範囲外のこと
sys_dictionary の element=sys_id は6,008件でした。全テーブル数6,317件との差分(約300件)が何にあたるかは特定していません。データベースビューや、フィールドを持たない一部の中間テーブルが含まれている可能性はありますが、確認はしていません。
Next Experience やワークスペースの画面で、sys_id を調べる同等の手段があるかどうかは今回の検証範囲外です。
エクスポートの sysparm_default_export_fields=all は、確認した一覧以外の画面・他の出力形式でも同じ挙動になるかまでは確認していません。
Copy sys_id・Show XML に必要な ui/context_menu.copy_sysid などのUI権限が、具体的にどのロールへ割り当てられているかは、今回の調査では特定できていません。管理者ロールで表示されることのみ確認しています。
参考リンク
GlideRecord - Global(ServiceNow Docs / Zurich API Reference)
GlideRecord - Scoped(ServiceNow Docs / Zurich API Reference)
GlideForm (g_form) - Client(ServiceNow Docs / Zurich API Reference)
Belly of the Beast: GUIDs and the sys_id(ServiceNow Community)
"Grab sys_id from Selected Record(s)" Tool(ServiceNow Community)