
エンコードクエリ演算子図鑑:^OR・IN・LIKE・ISEMPTYを実機で
開発ハンズオンシリーズの4回目です。①のはじめてのGlideRecordで検索と更新を、②で件数の集計を、③のドット・ウォークで参照先の項目の辿り方を動かしてきました。今回のテーマは、②で少しだけ触った addEncodedQuery に渡す文字列、つまり エンコードクエリの演算子 です。
②では「一覧画面で組んだ絞り込みを、そのままコードの条件に持ち込める」という話を、さらっと通り過ぎました。そこで渡していた文字列の中身が、今回の主役になります。^OR(または)・IN(いずれか)・LIKE(部分一致)・ISEMPTY(空)。名前だけ見ると呪文のようですが、ひとつずつ実機の件数で確かめれば、どれも素直な意味しか持っていません。
難しい準備は要りません。コードをコピーして Scripts - Background に貼り、Run script を押すだけ。この記事に出てくる件数は、すべて筆者の PDI で実際に流した結果です。演算子の名前を暗記するより、件数がどう動くかを目で追うほうが、記憶にずっと長く残りますよ。まだ①③を読んでいない方は、先に目を通しておくと、今回の話が地続きに感じられるはずです。
この記事は ServiceNow の PDI(無料の個人検証環境)Zurich / OOTB で実機実行した記録です。件数は Scripts - Background の実行結果で、REST でも二重確認しました(確認日 2026-07-19)。本番環境では実行しないでください。
エンコードクエリとは
エンコードクエリは、ひとことで言うと 「一覧のフィルタを1本の文字列で表したもの」 です。ServiceNow の一覧画面でフィルタを組むと、条件がいくつも積み上がりますよね。あの積み上がった条件を、機械が読める1行の文字列に畳んだもの。それがエンコードクエリです。区切り文字は ^(ハット記号)で、これが条件と条件の「かつ(AND)」を表します。
たとえば active=true^priority=1 なら、「active が true」かつ「priority が 1」の2条件です。^ の左右をそれぞれ独立した条件として読み、あいだの ^ を「なおかつ」と訳せば、長い文字列でも頭から順に読めます。仕組みは、これだけ。少し複雑な例を分解してみましょう。

図の一番上にある active=true^priorityIN1,2^ORshort_descriptionLIKEemail は、3つの部品でできています。active=true(未解決)、priorityIN1,2(優先度が1か2)、ORshort_descriptionLIKEemail(または説明に email を含む)。^ は AND、^OR は OR。区切り文字さえ見つければ、どんなに長い文字列でも部品の集まりへほどけます。今回はこの部品ひとつひとつ、つまり個々の演算子に注目します。順番に見ましょう。
この文字列は、手で全部書く必要はありません。一覧画面でフィルタを組み、右クリックの「Copy query」で丸ごと取り出せます。取り出した文字列を addEncodedQuery() に渡せば、画面で見たままの絞り込みがコードで再現できるわけです。読める・書ける・取り出せる。この3つがそろうと、一覧とスクリプトの距離がぐっと縮まります。効きます。
エンコードクエリが読めると、日々の調べ物がずいぶん楽になります。誰かが書いた Business Rule の条件、レポートの絞り込み、通知の送信条件。ServiceNow のあちこちに、この文字列は顔を出します。ブラウザのアドレスバーに並ぶ sysparm_query= から始まる長い呪文も、正体は同じエンコードクエリです。区切りの ^ を目印にして、部品へほどく。その読み方さえ身につけば、初めて見る条件でも臆さず中身を追えます。今回ひとつずつ演算子を確かめるのは、この「読む力」を土台から固めておきたいからでもあります。
^OR:または
まずは「または」から。優先度が 1 か 5 のインシデントを数えてみましょう。エンコードクエリでは ^OR を条件のあいだに挟みます。
var gr = new GlideRecord('incident');
gr.addEncodedQuery('priority=1^ORpriority=5');
gr.query();
gs.info('priority=1^ORpriority=5 : ' + gr.getRowCount() + ' 件');
結果は 49件 でした。内訳を確かめると、優先度1が28件、優先度5が21件。足すと49件ですから、^OR が両方の条件をきちんと拾っているのが見て取れます。片方だけなら28件か21件で止まるはずのところ、どちらかに当てはまれば拾う。これが「または」の働きです。理屈はいたって単純。
ここで押さえたいのは、区切り文字の顔が2つあること。ただの ^ は「かつ(AND)」で条件を絞り込みますが、^OR は「または」で条件を広げます。同じハット記号でも、うしろに OR が付くと意味が反転するわけですね。実務では「P1 と P5 だけ今すぐ見たい」といった、飛び飛びの値をまとめて拾う場面でよく使います。なお ^ と ^OR を1本に混ぜると優先順位の話が出てきますが、そこは今回の範囲を超えるので、まずは単純な OR の形だけ手になじませておきましょう。
もうひとつ、^OR を扱ううえで知っておくと安心な性質があります。priority=1^ORpriority=5 のように、同じ項目へ OR をかけるのが、いちばん素直な使い方です。別々の項目にまたがる OR も文法としては書けます。ただ、そこでは ^(AND)との優先順位がからんで、読み手が意図を取り違えやすくなります。だから慣れないうちは、ひとつの項目に対する「1 か 5 か」という単純な形で ^OR を使うのがおすすめ。込み入った条件を1本の文字列へ無理に詰め込むより、画面で組んで Copy query に任せたほうが、事故が起きません。無理は禁物。
IN:いずれか
次は「いずれか」。候補の値が2つ3つと増えてきたとき、^OR を何度も書くのは骨が折れます。そんなときに効くのが IN です。カンマ区切りで値を並べるだけで済みます。
var gr = new GlideRecord('incident');
gr.addEncodedQuery('priorityIN1,2,3');
gr.query();
gs.info('priorityIN1,2,3 : ' + gr.getRowCount() + ' 件');
こちらは 45件。優先度1が28件、2が4件、3が13件で、合わせて45件になりました。priorityIN1,2,3 は、意味としては priority=1^ORpriority=2^ORpriority=3 とまったく同じです。同じ条件を、片方は長々と、もう片方はすっきりと書ける。読みやすさが段違いですよね。短いは正義。
値の候補が増えるほど、IN のありがたみは増します。3つ4つ5つと ^OR を連ねた文字列は、目で追うだけでも疲れますし、書き間違いも起きやすい。IN なら候補をカンマでつなぐだけなので、条件の中身が一目で分かります。逆の「どれでもない」は NOT IN で書けて、priorityNOT IN4,5 のように使えます。状態や区分のように、決まった選択肢の中から数個を選ぶ絞り込みでは、IN が第一候補になると覚えておくと便利です。
内訳を自分の手で足し戻すと、IN の働きがもっと腑に落ちます。今回の45件は、優先度1が28件・2が4件・3が13件の合わせ技でした。試しに priority=1・priority=2・priority=3 を単独で流せば、28・4・13という数がばらばらに返ってきます。この3つを足した数が、IN の45件とちょうど重なる。演算子が値をどう束ねているのかは、こうやって分解して足し戻すと、目に見える形で確かめられますよ。
LIKE:部分一致
数値の次は文字です。「説明のどこかに email という語を含むもの」を探すには、部分一致の LIKE を使います。今回は件数だけでなく、ヒットした番号と説明も一緒に出してみましょう。
var gr = new GlideRecord('incident');
gr.addEncodedQuery('short_descriptionLIKEemail');
gr.query();
gs.info('short_descriptionLIKEemail : ' + gr.getRowCount() + ' 件');
while (gr.next()) {
gs.info(' ' + gr.getValue('number') + ' : ' + gr.getValue('short_description'));
}
ヒットは 8件。中身を眺めると、面白いことに気づきます。Can't read email のように小文字の email もあれば、EMAIL Server Down Again のように大文字の EMAIL もある。どちらもまとめて拾えています。ここが肝心。LIKE は大文字小文字を区別しません。だから検索する側は、原文が email か EMAIL か Email かを気に病まずに済みます。
この「区別しない」という性質は、実務ではありがたい場面が多いはずです。ユーザーが入力した説明文の大小表記はバラバラですから、区別してしまうと取りこぼしが出ます。LIKE なら表記ゆれをまたいで拾えるので、キーワード検索の下地として頼りになります。位置を絞りたいときは仲間の演算子が使えて、前方一致なら STARTSWITH、後方一致なら ENDSWITH。「INC001 で始まる番号」を探すなら numberSTARTSWITHINC001、といった具合です。どこに含まれてもよいのが LIKE、頭に来るものだけが STARTSWITH、と役割で覚えておくと迷いません。
便利な部分一致には、気をつけどころもひとつあります。拾えすぎることがある点です。email を探したつもりが、対象データによっては emailing や webmail のような語まで巻き込む場合があります。今回の8件は、どれも「email」という語そのものを含んでいて素直でした。それでも、扱うテーブルによっては意図しないヒットが混じり得ます。狙いを鋭くしたいときは、STARTSWITH で頭を固定するか、別の条件を ^ で足して範囲を締める。この一手間で、部分一致の取りこぼしと拾いすぎのバランスが取れます。
ISEMPTY / ISNOTEMPTY:空か、空でないか
最後は「値が入っているか、いないか」。担当グループが未設定のインシデントと、設定済みのインシデントを、それぞれ数えてみます。空を調べるのが ISEMPTY、空でないほうが ISNOTEMPTY です。
var a = new GlideRecord('incident');
a.addEncodedQuery('assignment_groupISEMPTY');
a.query();
gs.info('assignment_groupISEMPTY : ' + a.getRowCount() + ' 件');
var b = new GlideRecord('incident');
b.addEncodedQuery('assignment_groupISNOTEMPTY');
b.query();
gs.info('assignment_groupISNOTEMPTY : ' + b.getRowCount() + ' 件');
空が 29件、空でないほうが 42件。この2つを足すと71件になり、これはインシデントの総数と一致します。担当グループを持つものと持たないもので、テーブル全体をちょうど二分できたわけですね。きれいに割り切れました。「担当が決まっていない放置チケットを洗い出す」といった棚卸しで、ISEMPTY は日常的に活躍します。
ここでひとつ、初めて必ずつまずく落とし穴があります。ISEMPTY と ISNOTEMPTY には、= を付けません。うっかり assignment_group=ISEMPTY と書きたくなりますよね。ところがこう書くと、ServiceNow は「担当グループの値が、文字列 "ISEMPTY" にぴったり一致するもの」を探しに行きます。そんなレコードは存在しないので、結果は必ず0件。筆者が実際に = 付きで流したときも、きれいに0件でした。空を調べる系の演算子は、それ自体が「=空」という意味を含んでいるので、イコールはいらない。この一点だけ、指に覚えさせておいてください。
空かどうかを見る場面は、運用の現場に驚くほど多くあります。担当グループが空のインシデントは、宙に浮いた未割り当てチケットの候補。解決日時が空のものは、まだ終わっていない案件。コメントや作業メモが空のままなら、対応の記録が抜けているサインと読めます。ISEMPTY と ISNOTEMPTY は、そうした「入っているか、いないか」の棚卸しを、たった1行で担ってくれます。しかも今回のように総数を2つへきれいに割れるので、件数の検算にも重宝します。空の判定は地味ですが、実務でいちばん出番の多い演算子のひとつです。
演算子早見表
ここまでで4種類の演算子を動かしました。よく使うものを、構文の形といっしょに一覧へまとめておきます。手を動かす前に、ちらっと眺める用として使ってください。

表に並んだ演算子は、役割で束ねると覚えやすくなります。= と != は等号系、^ と ^OR はつなぎ役。IN・LIKE・STARTSWITH は集合や文字の一致で、ISEMPTY と ISNOTEMPTY は空の判定です。末尾の ORDERBY は並べ替え。こうしてグループで捉えると、10個近くあっても頭に入りやすくなります。全部を丸暗記する必要はありません。「こういう演算子があったな」と思い出せさえすれば、この表に戻ってくればよいのですから。
今回の実測まとめ
今回コードで確かめた件数を、一枚の表にしておきます。数字はすべて、この記事のコードをそのまま流した結果です。

今回の件数を並べると、^OR が49件、IN が45件、LIKE が8件。ISEMPTY は29件で、ISNOTEMPTY は42件でした。あなたの PDI では、データの中身しだいで件数そのものは変わります。ただ、演算子の意味は同じです。ISEMPTY と ISNOTEMPTY を足せば総数になる、といった関係はそっくり再現できるはずです。件数の絶対値より、条件を変えたときの動きに目を向けてください。そこを見ると、演算子の手ざわりがつかめますよ。
件数は二重に確かめた
本文の件数は、Scripts - Background の出力をそのまま載せているだけではありません。同じ条件を REST の集計(stats の count)でも引き直し、両方の数字が一致することを確かめてから記事にしています。priority=1^ORpriority=5 が REST でも49件、priorityIN1,2,3 が45件、short_descriptionLIKEemail が8件。どれも Scripts - Background の値とぴったり重なりました。ずれはゼロ。
なぜわざわざ二度数えるのか。件数は記事の土台になる数字なので、片方の経路だけで信じたくないからです。スクリプトの書き間違いや、環境固有のクセで数がずれることは起こり得ます。入口を変えて同じ数が返れば、少なくとも「たまたま」ではないと言い切れる。地味な手間ですが、この一手間が数字の裏づけになります。手元の PDI で件数が近い値になれば、あなたの検証と記事の記録が、同じものを見ている証拠になりますね。
二重確認は、読者への小さな約束のようなものだと思っています。記事に載る数字が、たまたま合っていただけなのか、経路を変えても揺るがないのか。書き手には見分けが付きますが、読む側からは区別できません。だからせめて、出せる裏づけは先に出しておきたい。REST と Scripts - Background という別々の入口で、同じ件数が返った。その事実を添えておけば、あなたが手元で再現するときの安心材料になります。数字の正しさを主張するだけでなく、確かめ方まで見せておく。その積み重ねが、記事全体の信頼につながると考えています。
Copy query で手書きを減らす
ここまで演算子を手書きしてきましたが、複雑な条件を全部そらで書くのは、正直なところ骨が折れます。そこで実務では、一覧画面の力を借ります。②でも軽く触れたやり方で、これが速くて確実です。
手順はかんたん。まず incident の一覧画面でフィルタを組み、見たい条件を画面上で作ります。条件が決まったら、フィルタ行のうしろにある条件文(ブレッドクラム)を右クリックし、「Copy query」を選ぶだけ。すると active=true^priority=1^ORpriority=5 のようなエンコードクエリが、クリップボードに丸ごと収まります。あとはそれをコードの addEncodedQuery() に貼れば、画面で確かめた絞り込みがそのままスクリプトになります。
このやり方の良いところは、間違いが減ることです。演算子の綴りや ^ の位置を手で打つと、どうしても打ち間違いが混ざります。画面で組んだ条件はすでに動く形になっているので、それをコピーする限り、構文ミスは起こりません。画面で結果を目視してから貼れば、件数の見当も先に付きます。「画面で組んで、コピーして、貼る」。この流れを癖にしておくと、複雑な条件でも臆せず書けるようになりますよ。
取り出したエンコードクエリは、そのまま資産として残せます。よく使う絞り込みをコードのコメントに書き添えておけば、次に同じ条件を使うとき、また画面で組み直さずに済みます。チームで共有するときも、長い日本語の説明より、1行のエンコードクエリを見せるほうが正確です。条件の中身が、余計な解釈をはさまずに伝わります。画面とコードのあいだを、この短い文字列が橋渡ししてくれるわけですね。手で書く量が減るほど、綴り間違いから来る「なぜか0件」も自然に少なくなります。
よくあるつまずき
エンコードクエリで最初にハマりやすい点を、先回りして挙げておきます。どれも一度は通る道なので、知っておくと落ち着いて対処できます。身構えなくて平気です。
ISEMPTY に = を付ける:assignment_group=ISEMPTY と書くと、文字列 "ISEMPTY" との一致を探して0件になります。空系の演算子にイコールは付けません。
LIKE の大文字小文字を気にしすぎる:LIKE は大小を区別しないので、email でも EMAIL でも同じように拾います。表記ゆれを恐れなくて大丈夫です。
^ と ^OR を混同する:^ は「かつ」で条件を絞り、^OR は「または」で条件を広げます。うしろに OR が付くかどうかで意味が反転する点に注意しましょう。
手打ちで綴りを間違える:STARTSWITH や ISNOTEMPTY は綴りが長く、打ち間違えると黙って0件になります。不安なときは Copy query で取り出すのが安全です。
まとめ
今回は ^OR・IN・LIKE・ISEMPTY の4種類を、実機の件数で読み解きました。^OR は「または」で49件、IN は候補のいずれかで45件、LIKE は大小を区別しない部分一致で8件、ISEMPTY と ISNOTEMPTY は空の判定で29件と42件。演算子はどれも、名前のとおりの素直な意味しか持っていません。難しくありません。件数を目で追えば、その素直さがそのまま腑に落ちるはずです。
いちばんの近道は、読むだけで終わらせず、Scripts - Background で同じコードを流してみること。件数が記事とだいたい重なれば、その演算子はもうあなたの道具です。複雑な条件は Copy query で取り出せる、という逃げ道も手元にあります。あとは手を動かすだけ。まずは今日の4つを、自分の PDI で動かしてみてください。
次回は、日付を扱う GlideDateTime を実機で動かす予定です。「起票から何時間経ったか」といった経過時間の計算や、日付どうしの引き算を、コードでどう書くか。件数と同じように、実際の値を出しながら確かめていきます。数値・文字・空ときたので、次は時間。GlideRecord で扱うデータの主要な型が、これでひととおりそろいます。
その他、実機で確認した記録
用語
エンコードクエリ … 一覧のフィルタを1本の文字列で表したもの(区切りは ^)
addEncodedQuery … エンコードクエリの文字列を渡して検索条件にするメソッド
^(ハット) … 条件と条件の「かつ(AND)」
^OR … 条件と条件の「または(OR)」
IN / NOT IN … カンマ区切りの値のいずれか / どれでもない
LIKE / STARTSWITH / ENDSWITH … 部分一致 / 前方一致 / 後方一致(大小を区別しない)
ISEMPTY / ISNOTEMPTY … 空 / 空でない(= を付けない)
Copy query … 一覧画面の条件文を右クリックで取り出す操作
実行に使ったスクリプト
本文のコードは、そのまま Scripts - Background に貼れば動きます(実行は必ず PDI で)。件数はすべて筆者の PDI(Zurich / OOTB)で流した実画面で、REST の集計とも突き合わせて一致を確認しています。
調べるときの入口URL(先頭に自分のインスタンスを付ける)
/sys.scripts.do … Scripts - Background(今回コードを流した画面)
/incident_list.do?sysparm_query=priority=1^ORpriority=5 … ^OR の条件を画面で確認
/incident_list.do?sysparm_query=assignment_groupISEMPTY … 担当グループが空の一覧
/sys_dictionary_list.do?sysparm_query=name=incident … incident の項目定義(演算子を当てる項目名の確認)
実測の要点(再掲)
priority=1^ORpriority=5 … 49件(優先度1が28件 + 優先度5が21件)
priorityIN1,2,3 … 45件(28 + 4 + 13)。^OR 3連結と同義
short_descriptionLIKEemail … 8件(email / EMAIL 双方に一致)
assignment_groupISEMPTY … 29件 / assignment_groupISNOTEMPTY … 42件(合計71=総数)
assignment_group=ISEMPTY(= 付き)… 0件(文字列一致になる誤り)
検証範囲とおことわり
実行は PDI(Zurich / OOTB)の Scripts - Background・scope=global のみ。件数は執筆時点の値です。
^ と ^OR を混在させたときの優先順位(AND が塊になる挙動)の詳細は範囲外とし、今回は単純な OR のみ実測しました。
日付系の相対クエリ(javascript: 関数を使う書き方)は本記事では扱いません。次回の GlideDateTime で取り上げる予定です。