メインコンテンツへスキップ

レコードの 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権限が、具体的にどのロールへ割り当てられているかは、今回の調査では特定できていません。管理者ロールで表示されることのみ確認しています。

    参考リンク

     
     
    ServiceNowのPDI(Personal Developer Instance)を実機で観察して、Noteに記事を書いています 実装・運用・教育の現場視点で淡々と記録中です リクエストがあればその記事も書きます 個人の観察日記です

    あなたへのおすすめ