メインコンテンツへスキップ
見出し画像

問題管理モジュールのテーブル・フィールド構成


    Problemのフォームに並ぶ項目は、どこで定義されているのでしょうか。problem は task テーブルを継承しているため、項目の定義は複数の層に分かれています。原因調査・回避策・恒久対策を記録する項目を自社の運用に合わせて変えるとき、どの層を触るかで影響範囲が変わります。Australia の PDI をデフォルト設定のまま開き、102項目の内訳・型・既定値と、state系フィールドの二重構造を確かめました。

    検証環境:Australia PDI / OOTB / 2026-08-31 確認

    確認する項目

    • Problemの項目がproblemとtaskのどちらで定義されているか

    • problem_taskがproblemではなくtaskを直接継承する構造

    • 102項目がどの型で構成されているか

    • stateとproblem_stateという2つの状態フィールドの関係

    • incident.problem_idという辞書に存在しないフィールドの実態

    この記事の要点

    • problem_taskはtaskを直接継承する独立したテーブルで、problemとはきょうだい関係にある

    • state(101-107、105欠番)とは別にproblem_stateという整数フィールドが存在し、2件のBusiness Ruleで相互同期している

    • sys_dictionaryのmandatoryは0件で、必須はUIポリシー・データポリシー・ACLが決めている

    テーブルの継承構造

    実際のProblemフォームはこう見えます。この記事ではPRB0000001(Windows XP SP2 causing errors in Enterprise)を例に使います。


    画像

    画面上部には状態の進み具合を示すリボンがあり、Resolve・Re-Analyze・Accept Riskといったボタンが並びます。Priorityが5-Planningになっている点は、本記事の後半で扱う上書きの結果です。

    Problemはtaskテーブルを継承しています。ここまではIncidentと同じですが、子テーブルであるproblem_taskの継承先に、意外な点があります。


    画像

    sys_db_objectで3テーブルを並べると、継承関係が確認できます。


    画像

    「problem → problem_task」という3階層を想像しがちですが、実機のExtends欄はどちらもtaskです。problem_taskはtaskを頂点とする2階層で、problemとはきょうだい関係にあります。この構造には実務上の影響があります。problem固有のUI Actionや設定は、problem_task側には引き継がれません。problem用に用意したボタンや通知をproblem_taskでも使いたい場合は、problem_task側に個別に用意する必要があります。

    フィールドの総数と内訳

    sys_dictionaryを数えると、taskから継承する共通項目が71、problem固有が31、problem_task固有が16でした。


    画像


    画像

    Problemのフォームで扱える項目は、task由来71とproblem固有31を合わせた102項目です。problem_taskは71と16を合わせた87項目になります。

    型の分布

    102項目を型で分けると、Referenceが最多の27項目でした。


    画像

    Integerが12項目ある中に、stateとproblem_stateという2つの状態フィールドが並びます。この二重構造は、本記事の後半で扱う目玉のテーマです。

    HTML型は3項目(workaround/cause_notes/fix_notes)で、回避策・原因・恒久対策のメモをリッチテキストで記録します。Choice型は3項目(category/subcategory/resolution_code)で、いずれも文字列として保存されます。

    参照フィールドのつながり先

    Reference型27項目が、どのテーブルを指しているかを整理します。


    画像

    Userへの参照は9項目あります。段階ごとに別の項目で実施者を記録する設計です。

    • assigned_to:担当者

    • confirmed_by / fix_by / fix_communicated_by:確認・恒久対策・周知の実施者

    • reopened_by / resolved_by / workaround_communicated_by:再オープン・解決・回避策周知の実施者

    誰が確認し、誰が直し、誰が周知したかを、項目ごとに追跡できます。

    problem固有31項目のうち10項目がReference型で、参照先はほぼ「人」か「関連レコード」です。代表例は次のとおりです。

    • duplicate_of:重複元のProblem

    • primary_known_error_article:既知エラー記事

    • rfc:対策のためのChange

    • prb_model:Problem Model

    • first_reported_by_task:最初に報告したタスク(Incidentなど)への参照

    problem固有フィールドの約3分の1は、他のレコードとの結びつきを表すために存在します。

    Reference型以外にも、状態を数値やフラグで保持する固有項目があります。major_problem(重大プロブレムかどうかを示すフラグ)はデモデータ24件のうち0件でした。reopen_countとrelated_incidentsはどちらもIntegerで、既定値は0です。前者は再オープンの回数、後者は関連付けられたIncidentの件数を保持します。

    既定値が設定されているフィールド

    102項目のうち、既定値が設定されているのは24項目でした。


    画像

    5項目(number/opened_at/opened_by/sys_class_name/prb_model)はJavaScript式です。番号の採番、起票時刻の記録に加えて、prb_modelの既定値がProblem Model機能の関数呼び出しになっている点がProblem特有です。

    impactとurgencyの既定はどちらも3です。この組み合わせをProblem専用の優先度マトリクス(dl_problem_priority)に当てると3-Moderateになりますが、priority辞書の生の既定値は4のままです。この食い違いは、次の節で扱う上書きが解消しています。

    taskの定義をproblem用に上書きしている項目

    継承には第3の層があります。taskの定義を受け継ぎつつ、problemでだけ挙動を変える上書き(sys_dictionary_override)です。実測では12件が登録されていました。


    画像


    画像

    priorityとstateの2件が具体的です。

    priority:辞書の既定値4が、上書きで5に変わる

    sys_dictionaryのpriority辞書は既定値4(task由来の生値)のままですが、sys_dictionary_overrideのproblemの行がdefault_value=5に上書きしています。新規に作成したProblemのpriorityは、辞書だけを読むと4に見えて、実際は5(Planning=最低優先度)で始まります。辞書1箇所を読むだけでは実際の挙動が分からない、という上書きの効果を最も直接に示す例です。

    state:どの状態を「終了」とみなすかの定義

    属性にclose_states=107、default_work_state=102、default_close_state=107が入っています。Closed(107)を終了状態として扱う定義が、辞書の上書きとして書かれている形です。read_only=trueも同時に設定されており、フォーム上でstateを直接選べない理由もここにあります。

    この読み取り専用化は、辞書だけでなくUI Policy側にも重ねて設定されています。「Make Problem State read only」というUI Policyがproblemテーブルで有効になっており、辞書のread_only属性と合わせて二重の保護になっている構成です。

    上書きの仕組みは、自社のカスタマイズでも使え、taskの項目をproblemだけで変えたい場面で役立ちます。taskの辞書を直接変更するとIncident・Change・Catalog Taskへ波及するため、sys_dictionary_overrideにproblem用の行を足せば、taskの定義には触れずに済みます。

    必須項目を決めている仕組み

    sys_dictionaryのmandatoryがtrueの項目は、102項目のうち0件でした。


    画像

    実際に必須になる項目は、別の3つの仕組みで決まります。

    仕組みテーブルproblem向けの件数効く範囲UIポリシーsys_ui_policy15画面上のみデータポリシーsys_data_policy28画面・API・インポートすべてACL(write)sys_security_acl67書き込みそのものを止める

    データポリシー8件はすべてenforce_ui=trueです。resolution_codeがDuplicateのときは、duplicate_ofを必須にします。stateがFix in Progressのときは、cause_notesとfix_notesを必須にします。状態や解決コードに連動した条件が中心です。Incidentのデータポリシーは1件でした。Problemは8件で、解決プロセスの各段階の記録を細かく強制しています。

    problemを参照する実テーブルとincident.problem_idの謎

    Problemが他プロセスとどうつながるかを調べると、寄り道が必要になる箇所が1つあります。

    problemのduplicate_of(自己参照)とproblem_taskのproblemを除くと、problemを参照する実テーブルは他に見当たりません。sys_dictionaryをreference=problemで検索しても、この2件以外はvar__m_で始まるFlowの内部変数テーブルだけです。

    Incident側から見ると、さらに興味深い事実があります。incidentの辞書にも辞書上書きにもproblem_idという項目は存在しません。REST APIでsysparm_fields=number,problem_idを指定しても、返ってくるJSONのキーはnumberだけで、problem_id自体が含まれません。

    ところが、incident_list.do?sysparm_query=problem_idISNOTEMPTYというURLは実際に画面が開きます。


    画像

    この結果だけを見ると、problem_idという隠しフィールドに実データが入っているように見えます。実際に件数を数えると、返ってきた件数はincidentの全件数と完全に一致していました。ここで、実在しないダミーの項目名(例:totallyfakefieldxyz)を条件に指定した場合と比較します。両者はまったく同じ挙動でした。条件が黙って無視され、全件が返ります。一方でactive=trueのような実在する項目は正しく絞り込まれます。problem_idISNOTEMPTYが特定のレコードだけを絞り込んでいる証拠にはなりません。

    事実として確定できるのは次の3点です。

    1. incidentの辞書にも辞書上書きにもproblem_idは存在しない

    2. REST APIのフィールド一覧にもproblem_idは出てこない

    3. problem_idISNOTEMPTYという条件は、実在しない項目名を指定した場合と同じ挙動になる

    一方でACL(incident.problem_id、3件)・Business Rule(Problemが閉じたとき関連Incidentを更新するスクリプトの中のinc.addQuery("problem_id", current.sys_id)という一文)・プロパティ(problem.duplicate.records_to_moveの設定値)には、problem_idという名前が今も残っています。これらは実際に動く設定として登録済みです。

    ここから先は推測です。ACLやBusiness Ruleのスクリプト文字列には、今もproblem_idという名前が残っています。過去のバージョンでは実在する列だったが、その後の仕様変更で辞書側の定義だけが削除された、という経緯が考えられます。Business RuleのaddQuery("problem_id", ...)が実際にどう動くかは分かりません。GlideRecordのクエリ構築とREST APIのクエリ解釈は、実装が同じとは限らないためです。本調査は読み取り専用RESTの範囲にとどめ、断定は避けます。動かして確かめる場合は、Scripts - Backgroundで1件だけ実行し、影響範囲を先に見積もる進め方をすすめます。

    state(101-107、105欠番)に対してproblem_stateがもう1つある

    Problemの状態管理を理解するうえで、この記事でいちばん押さえておきたい構造です。


    画像

    stateの選択肢は6件です。

    • 101 New / 102 Assess / 103 Root Cause Analysis / 104 Fix in Progress / 106 Resolved / 107 Closed

    104の次が106で、105は欠番です。inactiveな選択肢を含めても105は存在しません。


    画像

    state(101-107)とは別に、problem_stateという整数フィールドが存在します。選択肢定義(sys_choice)を持たず、既定値は1です。この2つのフィールドは、2件のBusiness Ruleで相互に同期しています。


    画像

    Business Ruleorderwhen発火条件Copy State to Problem State0beforestateVALCHANGESCopy Problem State to State1,000,000beforeproblem_stateVALCHANGES

    orderが0と1,000,000という極端な数値になっているのは、保存処理の最初と最後に実行させるためです。stateが変わったら最初にproblem_stateへコピーし、保存処理の終わりにあらためてproblem_stateからstateへコピーし直します。新しい状態体系(state)を正として動かしながら、古い状態体系(problem_state)を欠かさず追随させる構成です。

    problem_stateは、Fix・Cause関連のBusiness Ruleの発火条件としても使われます。「problem_state.changesTo(4)」を条件に持つBusiness Ruleが複数あり、Known Error記事の自動作成や、関連Incidentへの通知がここから動く仕組みです。stateではなくproblem_stateを条件に使っているBusiness Ruleがあるため、片方だけを見ていると動きを見落とします。

    Known Error系フィールドの役割

    problem固有フィールドには、原因調査から恒久対策までを段階的に記録する一群があります。

    • known_error:既知エラーかどうかを示すTrue/False

    • primary_known_error_article:既知エラー記事(Known Error article)への参照

    • cause_notes:根本原因のメモ(HTML)

    • fix_notes:恒久対策のメモ(HTML)

    • workaround / workaround_applied:回避策の内容と、適用済みかどうか

    • resolution_code:解決の分類(fix_applied/risk_accepted/canceled/duplicateの4種)

    sys_documentationのhintを引用します。

    Root cause has been determined and there is a workaround but there is NO permanent fix

    (訳: 根本原因は特定済みで回避策もあるが、恒久的な対策はまだ無い)

    known_errorの公式説明です。原因が分かっている、回避策がある、恒久対策はまだ無い。この3条件が揃った状態がKnown Errorです。フィールドの説明文自体が、この3条件を定義しています。resolution_codeの4種類は、恒久対策に至るまでの分岐を表す項目です。risk_acceptedを選ぶと、resolved_atとclosed_atが同時にセットされます。Resolvedの段階を経ずに、直接Closedへ進む処理が別のBusiness Ruleで動く仕組みです。


    画像

    引用元: /sys_documentation_list.do?sysparm_query=nameINproblem,problem_task^hintISNOTEMPTY

    実機で気づいたこと

    参照フィールドの割合がIncidentよりずっと高い

    problem固有31項目のうち10項目、約3分の1がReference型でした。Incident固有22項目ではReference型は4項目だけです。

    Problemは1件で完結する記録というより、原因調査の過程で人・Known Error記事・Change・元のProblemへとつながっていく記録に近い作りです。フィールドの型の内訳だけで、そのテーブルが何のために存在するかがある程度読み取れます。

    state系の項目を条件に使うときは、どちらの発火元か確認する

    stateとproblem_stateはBusiness Ruleで同期しているため、通常は値が一致します。ただし同期が走るのはbeforeのタイミングで、保存処理の最初(order=0)と最後(order=1,000,000)の2回に分かれる点に注意してください。保存処理の途中で参照すると、一時的に食い違ったままの値を読んでしまうことがあります。

    自社でBusiness Ruleやレポート条件を追加するときは、stateとproblem_stateのどちらを見ている既存ロジックがあるかを先に確認します。新規に条件を書くなら、公式のstateモデルに沿ったstateを使うほうが安全です。

    problem_idの謎は、メタデータだけを見ていては気づけない

    辞書・辞書上書き・REST APIのフィールド一覧という3つのメタデータを見る限り、incident.problem_idは存在しないという結論になります。一方でACL・Business Rule・プロパティという「動く設定」の側には、この名前が明確に残っています。

    自社の環境を調査するときも同じ手順が使えます。フィールドが本当に無いかを確認するなら、辞書だけでなくACL名・スクリプトの文字列・プロパティの値まで横断して検索します。辞書に見当たらないというだけで、関連する設定まで無いと決めつけるのは早計です。

    実務で順番に検討する箇所

    自社向けにProblemの項目を設計・調査するとき、確認する順序を決めておくと迷いません。


    画像
    1. 追加先の判断:Problemだけで使うか、他のtask系テーブルでも使うか。後者ならtaskに足す

    2. problem_taskの扱い:problem固有の設定を引き継がない独立テーブルだと意識する

    3. 既定値の確認先:辞書の生値だけでなく、sys_dictionary_overrideに上書きが無いかを確認する

    4. state系の実装:新規ロジックはstateを条件に使う。problem_stateを条件にした既存ロジックの有無を先に洗い出す

    5. 必須の実現方法:画面だけならUIポリシー、API経由も止めるならデータポリシー

    6. 他プロセスとの接続:Reference型フィールドの参照先を一覧化してから設計に入る

    7. メタデータに無い設定の確認:辞書に無い項目名は、ACL名・スクリプト文字列・プロパティの値まで検索してから判断する

    用語

    • OOTB:Out of the Box。プラグイン追加やカスタマイズを行っていない、製品のデフォルト状態

    • PDI:Personal Developer Instance。ServiceNowが無償で提供する個人検証用インスタンス

    • 辞書(Dictionary):sys_dictionary。テーブルの各項目の型・長さ・既定値を定義する場所

    • 辞書オーバーライド:sys_dictionary_override。継承元の定義を子テーブルだけで変える仕組み

    • Known Error(既知エラー):原因は特定済み、回避策あり、恒久対策はまだ無い状態

    検証範囲とおことわり

    • 検証環境:Australia PDI / OOTB / 2026-08-31確認

    • 件数はすべてOOTBの定義の数です。本番環境やカスタマイズ済み環境では異なります

    • UIポリシー15件・データポリシー8件の条件式の中身は、本シリーズ第6巻「問題管理モジュールの自動設定構成」で扱います

    • ACL 146件の内訳は、本シリーズ第3巻「問題管理モジュールのロール」で扱います

    • Business Rule 25件の実行順・スクリプト全文は、本シリーズ第6巻・第7巻およびSN-Platform-215の記事を参照してください

    • incident.problem_idの謎は、Flow Designerのサブフロー内部までは展開していません。事実として確定した範囲と推測は分けて記載しています

    付録:自分の環境で確認するときのURL

    • problemの項目定義:/sys_dictionary_list.do?sysparm_query=name=problem^elementISNOTEMPTY

    • problem_taskの項目定義:/sys_dictionary_list.do?sysparm_query=name=problem_task^elementISNOTEMPTY

    • 継承関係:/sys_db_object_list.do?sysparm_query=nameINproblem,problem_task,task

    • 上書きの定義:/sys_dictionary_override_list.do?sysparm_query=name=problem

    • stateの選択肢:/sys_choice_list.do?sysparm_query=name=problem^element=state^ORDERBYsequence

    • state同期のBusiness Rule:/sys_script_list.do?sysparm_query=collection=problem^nameLIKECopy

    • データポリシー:/sys_data_policy2_list.do?sysparm_query=model_table=problem

    引用した公式説明を実機で確認する方法

    この記事で引用した説明文は、ServiceNowが製品に同梱しているフィールドのドキュメントです。次のURLを自分のインスタンスで開くと、同じ記述が見つかります。

    • フィールドの公式説明(引用元):/sys_documentation_list.do?sysparm_query=nameINproblem,problem_task^hintISNOTEMPTY

    関連記事

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

    あなたへのおすすめ