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

Save filterの実体は1テーブル(sys_filter)


    ServiceNow の一覧画面で条件を組んで「Save filter」を押すと、その絞り込みが名前付きで残り、次からワンクリックで呼び出せます。この「保存したフィルタ」がどのテーブルに、どんな形で保存されているのかは、画面だけ見ていると見えてきません。

    実体は sys_filter(Filter) という1テーブルです。1つの保存フィルタが1レコードになり、「どのテーブルを」「どんな条件で」絞るか、そして「誰に見せるか」を保持します。この記事では sys_filter の構造と、対象テーブルの分布、共有範囲の決まり方を、PDI(Zurich)の OOTB で確認した実測値とともに示します。

    ServiceNow の一覧やフィルタは触っているが、保存フィルタの裏側のテーブルをこれから確認したい管理者・開発者を想定しています。sys_filter の固有フィールド、filter 文字列の中身、共有(user / group / roles)、お気に入りやモジュールでの再利用先を順に見ます。

    この記事で分かること

    • 保存フィルタの実体が sys_filter(1フィルタ=1レコード)であること

    • sys_filter が table(対象テーブル)と filter(エンコード済みクエリ)で一覧を再現すること

    • user / group / roles の値で共有範囲が決まること(user 空なら共有、値ありなら個人)

    • 今回の PDI では対象テーブルが cmdb_ci / incident に偏っていたこと

    • sys_filter にひも付く設定がほぼ ACL だけで、Business Rule などが 0 だったこと

    • 保存した条件が、モジュールやレポートの filter として再利用されること

    この記事の内容は ServiceNow の PDI(Personal Developer Instance)Zurich(ズーリッヒ)リリースの OOTB(初期設定)で確認した個人メモです。本番環境やカスタマイズ済み環境では、フィルタの件数・対象テーブル・共有設定が異なる場合があります。


    保存フィルタ(sys_filter)とは

    保存フィルタは、一覧画面で組んだ絞り込み条件に名前を付けて残したものです。リスト画面上部の breadcrumb に「Active = true」「Assigned to = (empty)」のように並ぶ条件、あれをそのまま保存して再利用する仕組みです。

    下は incident の一覧を「active=true かつ assigned_to=NULL(担当者なし)」で絞った状態です。上の breadcrumb に条件が表示されています。この条件に名前を付けて保存したものが sys_filter のレコードになります。


    画像

    保存した条件は、System Definition > Filters(テーブル名 sys_filter)に集まります。今回確認した PDI(Zurich / OOTB)では、sys_filter に 45 件 のフィルタがありました。一覧には Title(名前)・Table(対象テーブル)・Filter(条件文字列)・User(持ち主)といった列が並びます。


    画像

    保存フィルタを OOTB のレコードとして読めるのがこの一覧の利点です。incident の「Active」や cmdb_ci の「Servers」のような既定フィルタが、どんな条件で組まれているかを直接確認できます。


    sys_filter の構造と継承

    sys_filter は task 系のテーブルではなく、sys_metadata(Application File)を継承しています。なぜメタデータ扱いかというと、保存フィルタは業務データではなく「設定」であり、Update Set に載せて環境間で持ち運べるようにしてあるためです。


    画像

    今回確認した PDI(Zurich / OOTB)では、次の構造でした。

    • sys_filter(Filter) … super_class が sys_metadata(Application File)で、固有フィールドは11です。

    • sys_metadata … super_class が空のルート基底テーブルです。

    • 中心になる参照は user(→ sys_user) と group(→ sys_user_group) で、共有範囲を指します。

    テーブル定義は、次のURLで確認できます(先頭の <YourInstance> は自分のインスタンスに置き換えてください)。

    https://<YourInstance>/sys_db_object_list.do?sysparm_query=name=sys_filter


    画像

    sys_filter の主なフィールド

    sys_filter のレコードは、「どのテーブルを」「どんな条件で」「誰に見せるか」を表す項目を持ちます。役割で分けると、対象・条件・共有・補助に整理できます。


    画像

    中心になるのは次の3つです。ラベルは画面上の表示名で記載します。

    • table(Table) … 絞り込む対象テーブル名。incident なら incident、CI なら cmdb_ci が入ります。

    • filter(Filter) … エンコード済みのクエリ文字列。たとえば active=true^assigned_to=NULL のように、^ が AND、= が等価条件を表します。javascript:gs.user_id() のような動的値も入ります。

    • user(User → sys_user)/ group(Group → sys_user_group)/ roles(Roles) … 共有範囲を決める項目。後述します。

    補助項目として title(表示名)、mobile(モバイル用か)、last_used(最終使用日時)、sys_domain(ドメイン分離用)があります。

    このうち filter フィールドが保存フィルタの本体です。一覧画面の条件ビルダーで組んだ AND / OR の条件が、この1本の文字列に直列化されて保存されます。だから sys_filter のレコードを開くと、保存時の条件ビルダーがそのまま復元されて表示されます。


    画像

    全フィールドは、次のURLで一覧できます。

    https://<YourInstance>/sys_dictionary_list.do?sysparm_query=name=sys_filter^elementISNOTEMPTY


    画像

    条件を保存してから再利用するまで

    保存フィルタは、一覧で条件を組む → 名前と共有範囲を付けて保存する → sys_filter に1レコードできる、という流れで生まれます。


    画像

    保存したフィルタは、リストメニューの Filters から呼び出すと、同じ filter 文字列が一覧に適用されます。保存フィルタは条件そのものを持たず、「条件文字列を名前付きで覚えておく」だけなので、呼び出すたびに最新のデータに対して同じ絞り込みが走ります。たとえば「Active - Unassigned」を開けば、その時点で担当者のいないアクティブな incident が並びます。


    共有範囲(user / group / roles)

    保存フィルタを誰に見せるかは、user / group / roles の3項目で決まります。判断はシンプルで、user に値が入っていれば本人だけの個人フィルタ、user が空なら全員に見える共有フィルタです。


    画像

    今回確認した PDI(Zurich / OOTB)の45件は、共有範囲が次のように偏っていました。

    • user が空 … 44 件(全員に見えるシステム既定フィルタ)

    • user に値あり … 1 件(個人フィルタ。title=myfilter、対象 scan_check_suite、持ち主 System Administrator)

    • group に値あり … 0 件

    • roles に値あり … 0 件

    • mobile=true … 0 件

    OOTB の保存フィルタはほぼ全部が user 空の共有フィルタで、group 共有・roles 制限・モバイル専用は今回の初期状態では使われていませんでした。

    共有できるかどうかはロールで制御されます。公式ドキュメントによると、フィルタをグループに割り当てるには filter_group ロール、全員向けの共有にするには filter_global ロールが要ります。これらを持たないユーザーが保存すると、自分の user が入った個人フィルタになります。なぜそうするかというと、誰でも全員向けフィルタを量産できると一覧メニューが共有フィルタで溢れてしまうため、共有の発行を権限で絞っているからです。

    今回の PDI では group / roles が 0 件のため、グループ共有・ロール制限の実際の動作までは確認できていません(検証範囲外)。

    https://<YourInstance>/sys_filter_list.do?sysparm_query=userISNOTEMPTY

    対象テーブルの分布

    保存フィルタは、どのテーブルに向けて作られているかで性格が変わります。今回の45件を table(対象テーブル)で集計すると、distinct 20 種類に分かれていました。


    画像

    上位は cmdb_ci が 9 件、incident が 7 件、sys_properties が 5 件 でした。cmdb_ci のフィルタは「Servers」「Databases」「Network Gear」のように sys_class_name=cmdb_ci_server など CI クラスで切るものが多くあります。CMDB の広いクラス階層を一覧で扱うための既定フィルタが揃っています。incident は「Active」「Closed」「Assigned to me」のような運用でよく使う切り口でした。

    filter 文字列の組み立ては、どのテーブルでも共通です。^(AND)でつなぎ、= や NULL、javascript: の動的値を組み合わせます。たとえば incident「Assigned to me」は active=true^assigned_to=javascript:gs.user_id() です。ログインユーザーに依存する条件を1本の文字列に収めています。


    sys_filter にひも付く設定

    保存フィルタの挙動が、フィールド定義以外でどう制御されているかも確認しました。結果は、スクリプト系の設定がほぼ無く、ほとんどが Access Control(ACL)でした。


    画像

    今回確認した PDI(Zurich / OOTB・active 中心・2026-06-21 確認)では、次のとおりでした。

    • Business Rules(sys_script)… 0(active も全件も 0)

    • Client Scripts / UI Policies / UI Actions / Choices … いずれも 0

    • Access Controls(sys_security_acl・テーブル)… 18

    • Access Controls(フィールド単位)… 10

    ACL の operation を見ると、create 5 / read 4 / write 4 / delete 3 ほかでした。作成(create)の権限が他より細かく分かれているのが特徴です。保存フィルタは「誰がどの範囲のフィルタを作れるか」が重要なので、create を細分化して共有フィルタの発行を統制していると読めます。

    ここから言えるのは、sys_filter の振る舞いは業務ロジック(Business Rule など)ではなく、ほぼ ACL とロールで決まるということです。フィルタが保存できない・共有できないといった事象を調べるときは、まず ACL を見ます。それでも分からなければ、ロール(filter_global / filter_group)を確認するのが近道です。

    自分のインスタンスでは、次のURLで各一覧を開けます。

    ACL(テーブル)  : https://<YourInstance>/sys_security_acl_list.do?sysparm_query=name=sys_filter
    ACL(フィールド): https://<YourInstance>/sys_security_acl_list.do?sysparm_query=nameSTARTSWITHsys_filter.

    保存フィルタの再利用先

    保存した条件文字列は、sys_filter の一覧から呼び出すだけでなく、ほかの設定にも同じ形で埋め込まれます。filter は単なるエンコード済みクエリなので、フィルタを使う側のテーブルが直接持つこともできます。


    画像

    今回の PDI(Zurich / OOTB)で、filter 文字列を使う側の件数を確認しました。

    • sys_app_module.filter … アプリナビゲーターのモジュール 2705 件のうち、512 件が filter 文字列を直接持っていました。メニューをクリックした時点で一覧に絞り込みがかかるのはこのためです。

    • sys_report.filter … レポート定義 648 件。レポートの対象行を filter で絞ります。

    • sys_ui_bookmark … お気に入り 8 件。絞り込んだ一覧URLを登録します。

    sys_filter は「保存した条件のカタログ」、モジュールやレポートは「その条件を業務に組み込んだもの」と分けて見ると、同じ filter 文字列が複数の場所で再利用されている関係が整理できます。


    ServiceNow における保存フィルタのポイント

    • 保存フィルタの実体は sys_filter(Filter) に「1フィルタ=1レコード」で保存されます。今回の PDI では45件でした。

    • sys_filter は sys_metadata(Application File)を継承するメタデータで、固有フィールドは11でした。task 系ではありません。

    • 一覧の再現は table(対象テーブル)+ filter(エンコード済みクエリ) の2項目で決まります。filter は条件ビルダーを直列化した1本の文字列です。

    • 共有範囲は user / group / roles で決まり、user が空なら共有、値ありなら個人です。今回は44件が共有、1件が個人でした。

    • sys_filter には Business Rule などのスクリプトがほぼありません。挙動は ACL(18+10)とロール(filter_global / filter_group)で統制されていました。

    • 保存した filter 文字列は、モジュール(512件)やレポート(648件)でも再利用されます。

    保存フィルタを調べるときは、まず「このフィルタはどのテーブル(table)を、どんな条件(filter)で、誰に見せる(user / group / roles)ものか」を読みます。共有や作成の可否で迷ったら、ACL とロールを見るという順序が確実です。


    実機で気づいたこと

    • sys_filter には Business Rule も Client Script も UI Policy も0件でした。保存フィルタは条件を保存するだけの機能なので、何かしらの整合性チェック(filter 文字列の構文検証など)がサーバ側にあるだろうと予想していましたが、少なくとも今回の OOTB には見当たりませんでした。挙動を決めているのは ACL と filter_global / filter_group ロールだけで、フィルタが保存できないときはスクリプトではなく権限を疑うほうが近道だと分かりました。

    • ACL の operation 内訳を見ると、read / write / delete が3〜4件なのに対し create だけ5件と、作成の権限だけ細かく分かれていました。保存はできるが共有はできない、共有はできるが他人のフィルタは編集できない、といった線引きを、業務ロジックではなく権限設計だけで表現しているのが実機を見て分かった作りでした。

    • filter 文字列を持っているのは sys_filter だけではなく、モジュール(sys_app_module)が2705件中512件、レポート(sys_report)が648件、同じ書式の filter 文字列を自分の列として持っていました。保存フィルタという機能そのものより、^ 区切りのエンコード済みクエリという書式のほうが、プラットフォーム全体で使い回されている共通言語なのだと気づきました。


    次に読むなら

    次に確認するなら、次の2点です。

    • 共有を制御する filter_global / filter_group ロールの付与状況(sys_user_has_role)

    • filter 文字列を業務に埋め込む側である sys_app_module(モジュール)や sys_report(レポート)の構造

    保存フィルタ単体ではなく、「条件を保存する側(sys_filter)」と「条件を使う側(モジュール・レポート)」を分けて見ると、一覧の絞り込みがどこで決まっているかをたどりやすくなります。モジュール側は 左メニューもテーブルでできている(sys_app_module) で扱っています。レポートは別記事で扱う予定です。


    用語

    • PDI:Personal Developer Instance(無料の検証用インスタンス)

    • OOTB:Out of the Box(初期設定のまま)

    • 保存フィルタ(sys_filter):一覧の絞り込み条件を名前付きで保存したレコード

    • filter(エンコード済みクエリ):条件を直列化した文字列(^=AND, ==等価, javascript:=動的値)

    • breadcrumb:一覧上部に出る現在の絞り込み条件の表示

    • filter_global / filter_group:共有フィルタを作れるかを決めるロール

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

    自分のインスタンス名を先頭に付けると、同じ画面が開けます。

    テーブル定義   : sys_db_object_list.do?sysparm_query=name=sys_filter
    フィールド一覧 : sys_dictionary_list.do?sysparm_query=name=sys_filter^elementISNOTEMPTY
    保存フィルタ   : sys_filter_list.do?sysparm_query=ORDERBYtable
    個人フィルタ   : sys_filter_list.do?sysparm_query=userISNOTEMPTY
    ACL(テーブル): sys_security_acl_list.do?sysparm_query=name=sys_filter

    テーブルの基本

    • sys_filter … Label:Filter / Extends:Application File(sys_metadata)/ 固有フィールド 11

    • レコード件数:sys_filter 45(user 空 44 / user 有 1)/ 対象テーブル distinct 20

    共有範囲(実測)

    • user 空(共有フィルタ):44

    • user 有(個人フィルタ):1(title=myfilter / table=scan_check_suite / user=System Administrator)

    • group 有:0 / roles 有:0 / mobile=true:0

    対象テーブルの分布(実測・上位)

    • cmdb_ci 9 / incident 7 / sys_properties 5 / sc_req_item 3

    • change_request 2 / sc_request 2 / kb_feedback 2 / ecc_queue 2 / sys_portal_page 2

    • そのほか task など各 1(distinct 20)

    filter 文字列の例(実レコード)

    • incident「Active」:active=true

    • incident「Active - Unassigned」:assigned_to=NULL^active=true

    • incident「Assigned to me」:active=true^assigned_to=javascript:gs.user_id()

    • cmdb_ci「Servers」:sys_class_name=cmdb_ci_server

    • change_request「Closed」:active=false

    再利用先(filter 文字列を持つ側・実測)

    • sys_app_module(モジュール):2705 件中 filter あり 512

    • sys_report(レポート):648

    • sys_ui_bookmark(お気に入り):8

    周辺設定の件数(sys_filter・OOTB・active 中心)

    • Business Rules(sys_script)… 0

    • Client Scripts(sys_script_client)… 0

    • UI Policies(sys_ui_policy)… 0

    • UI Actions(sys_ui_action)… 0

    • Choices(sys_choice)… 0

    • Access Controls(sys_security_acl)… テーブル 18 + フィールド 10

    • ACL operation 内訳(テーブル18)

    • create 5 / read 4 / write 4 / delete 3

    • query_range 1 / conditional_table_query_range 1

    • Dictionary Entries(sys_dictionary)… 11(固有)

    sys_filter の固有フィールド(検索用)

    table, filter, title, user, group, roles, mobile, last_used, sys_domain, sys_domain_path, sys_id

    関連テーブル(検索用)

    • sys_metadata(基底)

    • sys_user(user)

    • sys_user_group(group)

    • sys_app_module(filter 再利用)

    • sys_report(filter 再利用)

    • sys_ui_bookmark(お気に入り)

    • sys_security_acl(権限)

    公式ドキュメント(Zurich)


    関連記事


    検証範囲とおことわり

    確認した範囲は次のとおりです。

    • sys_filter の階層(sys_metadata 継承)、固有フィールド数(11)、レコード件数(45)

    • 共有範囲の分布(user 空 44 / 有 1 / group・roles・mobile 0)

    • 対象テーブル分布(distinct 20)、filter 文字列の実例

    • 周辺設定件数(ACL 18+10、Business Rule ほか 0)

    • 再利用先の件数(モジュール 512 / レポート 648 / お気に入り 8)

    すべて PDI(Zurich / 2026-06-21 確認)の OOTB で取得しています。

    確認していない範囲(断定しません)は次のとおりです。

    • filter_global / filter_group ロールの付与状況と実動作

    • group 共有・roles 制限・mobile フィルタの動作(OOTB に該当レコードが 0 のため未観測)

    • 各 ACL の内部条件・スクリプト

    • お気に入り(sys_ui_bookmark)との実装上のひも付け

    • ワークスペース(UI Builder)系リストのフィルタ保存先

    これらは別記事で扱います。

    今回は PDI の OOTB(初期設定)を前提に、保存フィルタの構造を確認しました。実環境では、既存のカスタマイズや運用で、フィルタの件数・対象テーブル・共有設定が変わります。

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

    あなたへのおすすめ