# NXQLチュートリアル (クラシック)

## 概要 <a href="#nxqltutorial-classic-overview" id="nxqltutorial-classic-overview"></a>

Nexthink Query Language (NXQL) は、NXQL API を介して Nexthink Engine のインメモリデータベースをクエリするために設計された言語です。 この言語は、SQL に似たキーワードを使用していますが、LISP に類似した構文を持っています。

NXQL は、セレクタ言語（内部で開発された他の疑似SQL言語）の進化系です。 Finder、Portal、およびネクスシンクエンジンの統合された Lua インタープリタ内で動作する Lua スクリプトは、現在、エンジンをクエリするためにセレクタ言語を使用しています。 統合のために特別に設計され、速度向上を考慮しているため、NXQL は多くの分野でセレクタ言語を上回ります。 NXQL は、より複雑なクエリを記述できるようになり、オブジェクトのトラバーサルを制御できるため、クエリは通常より速く実行されます。

このチュートリアルは、NXQL を例を用いて学ぶ過程を案内するためのものです。 提案された順序で NXQL チュートリアルを進めることで、最大限に活用してください。

このチュートリアル内のクエリを実行するには、統合ツールキット モジュールを含むすべてのエンジンで入手可能な [NXQL エディタを使用してください](https://docs.nexthink.com/platform/ja/configuring_nexthink/bringing-data-into-your-nexthink-instance/integrating-nexthink-with-third-party-tools/api-and-integrations-classic/introducing-the-nxql-api-classic#introducingthenxqlapi-classic-testing-the-web-api-v2-with-the-nxql-editor)。 このチュートリアルの残りの部分は、管理者資格情報で NXQL エディタに認証されており、利用可能なすべてのデータ（コンピュータの名前やユーザー名など）を見るアクセス権を持っていることを前提としています。

## 最初のクエリ <a href="#nxqltutorial-classic-firstqueries" id="nxqltutorial-classic-firstqueries"></a>

利用可能なすべてのデバイスの一意識別子と名前のリストを取得するには、次のクエリを入力します：

```
(select (device_uid name) (from device))
```

クエリは開き括弧で始まり、閉じ括弧で終わることに注意してください。 クエリが適切に形成されるためには、開き括弧と閉じ括弧の数が均衡している必要があります。 クエリの構築を支援するために、必要に応じてシステムが自動的に欠落している括弧を最後に追加します。 クエリはキーワード `select` で始まるため、これを select ステートメントと呼びます。 select ステートメントには、取得するフィールドのリストと、フィールドが見つかるテーブルを指定する `from` 節が含まれます。

```
(select - select ステートメント
   (id name) - フィールドのリスト
   (from device)) - クエリ対象のテーブル
```

クエリ内では、フィールドにワイルドカード文字を含めることができます。 たとえば、デバイスの名前とアンチウイルスに関連するすべてのフィールドを取得するには、次のクエリを入力します：

```
(select (name *antivirus*) (from device))
```

フィールド名をタイプミスした場合、システムはエラーを示し、最も誤って入力したと思われる正確なフィールド名または、その入力に近いフィールドが存在しない場合は、その文脈で使用できるフィールド名の全リストを代替案として提案します。

デバイスのサブセットのみを取得するには、いくつかのフィールドの値によって結果をフィルタリングします。 たとえば、デバイス名が `NXT-DV10` であるデバイスのみを選択するには、次のクエリを入力します：

```
(select (name)
   (from device
   (where device
       (eq name (string "NXT-DV10")))))
```

`from` 節の中では、`where` 節は名前が NXT-DV10 に等しいデバイスのみを保持します。 `where` 節の最初の引数はフィルタが適用されるテーブルであり、2つ目の引数はフィルタそのものの式です。 フィルタは操作、フィールド名、型付き値の順で構成されます。 可能な操作には、`eq`、`ne`、`lt`、`le`、`gt`、`ge`（それぞれ、等しい、等しくない、未満、以下、より大きい、以上を意味します）があります。 値の型はフィールドの型と一致している必要があります。 [データモデル](https://docs.nexthink.com/platform/ja/configuring_nexthink/bringing-data-into-your-nexthink-instance/integrating-nexthink-with-third-party-tools/api-and-integrations-classic/nxql-api-classic/nxql-data-model-classic) でのすべてのフィールドの名前と型を確認してください。

### 論理的な AND 操作 <a href="#nxqltutorial-classic-logicalandoperation" id="nxqltutorial-classic-logicalandoperation"></a>

複数のフィルタに対して `where` 節を定義できます。 この場合、すべてのフィルタに一致するオブジェクトのみが選択されます。

たとえば、次のクエリは、Windows 7 を実行しており、アンチウイルスがインストールされていないデバイスのリストを返します：

```
(select (name os_version_and_architecture number_of_antiviruses)
   (from device
   (where device
       (eq os_version_and_architecture (pattern "Windows 7*"))
       (eq number_of_antiviruses (enum 0)))))
```

### 論理的な OR 操作 <a href="#nxqltutorial-classic-logicaloroperation" id="nxqltutorial-classic-logicaloroperation"></a>

一方、他のフィルタセットのいずれかに一致するオブジェクトを取得したい場合は、同一種類のオブジェクトに対して 2 つの `where` 節を書く必要があります。

たとえば、Windows 7 または Windows 8 / 8.1 を実行しているデバイスのリストを取得するには、次のクエリを入力します：

```
(select (name os_version_and_architecture number_of_antiviruses)
   (from device
       (where device
           (eq os_version_and_architecture (pattern "Windows 7*")))
       (where device
           (eq os_version_and_architecture (pattern "Windows 8*"))))
```

\
これが同じ種類のオブジェクトに対する `where` 節に有効であることを忘れないでください。 異なるテーブルのオブジェクトに条件を設定するより高度なクエリを書くとき、異なる種類のオブジェクトに対する複数の `where` 節は論理 AND として動作することを覚えておいてください。 以下に例を示します。

この段階で、Nexthink によって定義された任意のオブジェクトテーブルの任意のフィールドをクエリできるようになります。 デバイスとは異なる他のオブジェクト、例えばユーザーやバイナリを試して、NXQL に慣れてください。

## イベントの使用 <a href="#nxqltutorial-classic-usingevents" id="nxqltutorial-classic-usingevents"></a>

イベントは、特定の瞬間に IT インフラストラクチャ内で発生する出来事です。 すべてのイベントにはタイムスタンプがあるため、イベントは時間で順序付けることができます。 イベントは、インメモリデータベースの基本的な情報ユニットであるという点で、Nexthink テクノロジーの中心です。 それらが記述する出来事の種類に応じて、いくつかのタイプのイベントがあります。 各イベントタイプは、明確に定義された一連のオブジェクトにリンクされています。 例えば、**接続**イベントは、**ユーザー**、**デバイス**、**バイナリ**、**宛先**、および **ポート**オブジェクトにリンクされています。

データベースのイベント数は通常、他の種類のオブジェクトの数よりも何桁も大きいです。 デバイステーブルのようなオブジェクトテーブルには数百から1万の要素が含まれる場合がありますが、イベントテーブルには数千万の要素が含まれることがあります。 パフォーマンスの理由から、イベントを含むクエリのタイムスパンを設定する際にはこれを念頭に置くことが重要です。

クエリでは、次の 2 つの方法でイベントテーブルを使用できます：

* 指定された期間内に発生したイベントを直接選択します。 例えば、**firefox.exe**によって最後に行われた100件の接続を取得するには、前日を指定します：

```
(select (start_time end_time incoming_traffic outgoing_traffic)
   (from connection
       (where binary (eq executable_name (pattern firefox.exe)))
     (between midnight-1d midnight))
   (limit 100)
   (order_by start_time desc))
```

* 指定された期間内に発生するイベントにリンクされたオブジェクトを選択します。 例えば、前日に **firefox.exe** を使用して web にアクセスしたすべてのデバイスを取得するには：

```
(select (id name)
   (from device
       (with connection
           (where binary (eq executable_name (pattern firefox.exe)))
           (between midnight-1d midnight))))これは、以前のクエリと類似していますが、後者はwith節を導入しています。この節は、選択されたオブジェクトのリストを構築するために差し引かれるイベントのタイプを指定します。もちろん、対象オブジェクトにリンクされたイベントのみがトラバーサルに使用できます。
```

イベントに加えて、**with** 節は、デバイスとパッケージオブジェクトとの関係を表す **package** キーワードの前にも使用できます。以下で説明します。

### イベントによる論理操作 <a href="#nxqltutorial-classic-logicaloperationwithevents" id="nxqltutorial-classic-logicaloperationwithevents"></a>

クエリをさらに絞り込むことができます。 例えば、前日に **firefox.exe** を使用して **mail.google.com** にアクセスしたデバイスに関心があると仮定します：

```
(select (id name)
   (from device
       (with web_request
           (where binary (eq executable_name (pattern firefox.exe)))
           (where domain (eq name (string mail.google.com)))
        (between midnight-1d midnight))))
```

このクエリには、バイナリとドメインという異なる種類のオブジェクトに適用される 2 つの `where` 節があることに注意してください。 したがって、それらは論理 AND として動作し、2 つの条件が満たされる必要があります。

論理 OR として動作するには、`where` 節は同じ種類のオブジェクトに適用される必要があります。 例えば、前日 **mail.google.com** にアクセスするために **firefox.exe** に加えて **chrome.exe** を使用したデバイスを調べ、クエリを拡張します。以下のクエリを入力します：

```
(select (id name)
  (from device
      (with web_request
          (where binary (eq executable_name (pattern firefox.exe)))
          (where binary (eq executable_name (pattern chrome.exe)))
          (where domain (eq name (string mail.google.com)))
       (between midnight-1d midnight))))
```

一方、オリジナルのクエリをさらに詳細化し、**firefox.exe** のバージョンが **50** 未満のデバイスのみを返したい場合は、次の式を入力します：

```
(select (id name)
  (from device
      (with web_request
          (where binary (eq executable_name (pattern firefox.exe))
                        (lt version (pattern 50)))
          (where domain (eq name (string mail.google.com)))
       (between midnight-1d midnight))))
```

つまり、同じ種類のオブジェクトの *where* 節で複数の条件を設定します（この場合、**バイナリ** オブジェクト）。条件は論理 AND として結合されます。

最後に、異なる種類のオブジェクトの条件を論理 OR で組み合わせる必要がある稀な場合には、以下で文書化された **union** キーワードを使用します。

## 集計の計算 <a href="#nxqltutorial-classic-computingaggregates" id="nxqltutorial-classic-computingaggregates"></a>

イベントにリンクされたオブジェクトの選択は *集計* で強化できます。 集計は、選択されたすべてのイベントに対して、指定されたフィールドのカウント、合計または平均を計算する名前付き関数です。 例えば、**incoming\_traffic** 集計は、**with** 節で選択されたすべての **connection** または **web\_request** イベントの **incoming\_traffic** フィールドのすべての値を加算します。 集計は **with** 節内の **compute** 節で指定します。

一部の集計はその計算中にイベントの移動を必要とするため、集計を使用するときにイベントを使用する場合と同様のパフォーマンスの懸念があります。 さもないと、多くのイベントを移動する必要のある可能性があるクエリの時間間隔を制限することが重要です。 データモデルで **FP** としてマークされていない集計には、移動を制限するために **between** 節が必要です。 ただし、 **between** 節は指定可能な時間間隔を厳密に制限しません。 特にクエリが定期的に繰り返される場合は、合理的な時間間隔を設定する責任があります。

例えば、過去 7 日間に **mail.google.com** に対して行われたすべての web リクエストの各デバイスの受信トラフィックを計算するには、次のクエリを記述します：

```
(select (id name)
   (from device
       (with web_request
       (where domain
           (eq name (string mail.google.com)))
       (compute incoming_traffic)
       (between midnight-7d midnight))))
```

各イベントテーブルの集計リストは NXQL データモデルに定義されています。

この段階で、集計の値に基づいてデバイスをフィルタリングする方法を疑問に思うかもしれません。 前の例のように、昨日 1GB のデータを転送したデバイスを選択したいかもしれません。 これが **having** 節の目的であり、**with** 節内の **from** 節に現れるかもしれません。 もちろん、**having** 節でフィルタリングされた集計は最初に **compute** 節内で宣言されている必要があります。

```
(select (id name)
   (from device
       (with web_request
           (where domain
               (eq name
                   (string mail.google.com)))
           (compute incoming_traffic)
           (between midnight-7d midnight))
       (having
           (gt incoming_traffic
               (byte 1073741824))))
```

## カテゴリとカスタムフィールドの使用 <a href="#nxqltutorial-classic-usingcategoriesandcustomfields" id="nxqltutorial-classic-usingcategoriesandcustomfields"></a>

NXQL では、カテゴリとカスタムフィールドは同等に扱われます。 これらは通常のフィールドのように動作しますが、名前の前に **#** が付いています。 たとえば、デバイスのカテゴリとして Location があると仮定して、デバイスとその Location の一覧を取得するには、次のクエリを記述します：

```
(select (id name #Location) (from device))
```

また、カテゴリまたはカスタムフィールドをフィルタとして使用することもできます：

```
(select (id name)
   (from device
       (where device
           (eq #Location (enum Paris)))))
```

スペースまたは引用符を含むカテゴリまたはカスタムフィールドの名前は引用符で囲む必要があります：

```
(select (id name)
   (from device
       (where device
           (eq #"My Location" (enum Paris)))))
```

### キャンペーンのカスタムフィールド <a href="#nxqltutorial-classic-campaignscustomfields" id="nxqltutorial-classic-campaignscustomfields"></a>

キャンペーンの結果は、オブジェクト **user** のカスタムフィールドとして NXQL に表示されます。 キャンペーンに関連するカスタムフィールドの名前は次の形式を持ちます：

`#"campaign:Name of the campaign/Name of the question"`

カスタムフィールド名の先頭に **campaign:** キーワードを使用していることに注意してください。 例えば、キャンペーン **Laptop satisfaction** 内の質問 **Device preference** に対するすべてのユーザーの回答を知りたい場合、次のクエリを記述します：

```
(select (name #"campaign:Laptop satisfaction/Device preference")
   (from user))
```

*single answer* または *opinion scale* 質問への回答の基になる型は **string** 型です。 次に、複数回答質問への回答の基になる型は、文字列のリストです。 回答の値を `eq` と `ne` 演算子で比較します（回答値を比較するための他の演算子は使用できません）。 例えば、**Device preference** の単回答質問で **No** と答えなかったすべてのユーザーの名前と実際の回答を得るには、次のクエリを記述します：

```
(select (name #"campaign:Laptop satisfaction/Device preference")
   (from user
       (where user (ne #"campaign:Laptop satisfaction/Device preference"
                   (string "No")))))
```

同様に、特定の単回答または意見尺度質問にまだ回答していないユーザーを選択するには、空文字列と比較します：

```
(select (name #"campaign:Laptop satisfaction/Device preference")
   (from user
       (where user (eq #"campaign:Laptop satisfaction/Device preference"
                   (string "")))))
```

複数回答質問の場合、ユーザーが回答で示した回答の組み合わせをクエリすることができます。 上記で説明した **where** 節で論理 AND および論理 OR 操作を使用するか、特定の組み合わせと正確に一致する値のリストを指定します。 例えば、キャンペーン **Laptop satisfaction** の **Positive points** 質問に対して **Speed** および **Size**（おそらく他のものも）と答えたユーザーを得るには、次のクエリを記述します：

```
(select (name #"campaign:Laptop satisfaction/Positive points")
   (from user
       (where user (eq #"campaign:Laptop satisfaction/Positive points"
                   (string "Speed"))
                   (eq #"campaign:Laptop satisfaction/Positive points"
                   (string "Size")))))
```

代わりに、**Speed** と **Size** のみ（他のものは何もない）と正確に回答したユーザーをクエリしたい場合は、それらをリストとして指定します：

```
(select (name #"campaign:Laptop satisfaction/Positive points")
   (from user
       (where user (eq #"campaign:Laptop satisfaction/Positive points"
                   (list ("Speed" "Size"))))))
```

または、**Speed** または **Size**（または両方）を選択したユーザーを取得するには、論理 OR バージョンのクエリを記述します：

```
(select (name #"campaign:Laptop satisfaction/Positive points")
   (from user
       (where user (eq #"campaign:Laptop satisfaction/Positive points"
                   (string "Speed")))
       (where user (eq #"campaign:Laptop satisfaction/Positive points"
                   (string "Size")))))
```

最後に、複数回答質問にまだ答えていないユーザーを取得するには、空文字列ではなく **nil** キーワードで比較します：

```
(select (name #"campaign:Laptop satisfaction/Positive points")
   (from user
       (where user (eq #"campaign:Laptop satisfaction/Positive points" nil))))
```

### スコアのカスタムフィールド <a href="#nxqltutorial-classic-scorescustomfields" id="nxqltutorial-classic-scorescustomfields"></a>

スコアは、オブジェクトの特別なカスタムフィールドとして NXQL を通じてアクセス可能です **device** または **user**。 スコアに関連するカスタムフィールドの名前は次の形式を持ちます：

`#"score:Name of the score definition/Name of the score"`

カスタムフィールド名の先頭に **score** キーワードを使用していることに注意してください。 例えば、すべてのデバイスの **ブート速度** リーフスコアを取得するには、以下のクエリを記述します。このスコアは、**デバイスパフォーマンス** スコア定義内にあります。

```
(select (name #"score:Device performance/Boot speed")
   (from device))
```

スコアは数値を保持しているため、スコアの基になる型はすべて **real** 型です。 スコアの値に条件を設定する例として、以下のクエリは、**ブート速度** スコアが 5.0 よりも高いすべてのデバイスを取得します：

```
(select (name #"score:Device performance/Boot speed")
   (from device
       (where device (gt #"score:Device performance/Boot speed"
                     (real 5.0)))))
```

数値以外にも、スコアには値がまったく設定されていない場合もあります。 空のスコアを持つオブジェクトをクエリするには、**eq**または**ne**演算子を使用してスコアの値を**nil**キーワードと比較します。 たとえば：

```
(select (name #"score:Device performance/Boot speed")
   (from device
       (where device (eq #"score:Device performance/Boot speed"
                      nil))))
```

### リモートアクションのカスタムフィールド <a href="#nxqltutorial-classic-remoteactionscustomfields" id="nxqltutorial-classic-remoteactionscustomfields"></a>

オブジェクト\_device\_の特別なカスタムフィールドにアクセスして、リモートアクションの実行結果やその他の情報をNXQLを通じて取得します。 リモートアクションに関連するカスタムフィールドの名前は以下の形式です：

`#"action:Name of the remote action/Name of the output or exec info"`

カスタムフィールドの名前の初めに**action**キーワードを使用していることに注意してください。 たとえば、すべてのデバイスでリモートアクション**Get Event Log**の**Execution status**を取得するには、以下のクエリを書きます：

```
(select (name #"action:Get Event Log/Execution status")
   (from device))
```

特定のリモートアクションにステータスがないデバイスをフィルタリングするには、ステータスの値を**nil**キーワードと比較します。 たとえば、リモートアクション**Get Event Log**に関連するすべてのデバイスで実行ステータスを取得するには、以下を入力します：

```
 (select (name #"action:Get Event Log/Execution status")
   (from device
       (where device (ne #"action:Get Event Log/Execution status"
                      nil))))
```

リモートアクションの結果（つまり、その\_出力\_値）はNXQLを通じてアクセス可能です。 NXQLクエリ内で、リモートアクションで定義された出力の名前を正確に入力してください。 出力の\_name\_は、Finderに表示される\_ラベル\_とは異なる場合がありますので注意してください。 たとえば、リモートアクション**Get Event Log**で生成されたファイルへのパスを取得するには（出力の名前**OutputFile**、ラベル**Output file**）、以下のクエリを書きます：

```
(select (name #"action:Get Event Log/OutputFile")
   (from device))
```

各出力値は、リモートアクションの定義に示される型です。 空の値を比較するには、数値出力の場合は`nil`、文字列型出力の場合は空文字列`""`を使用します。

## Platformの使用 <a href="#nxqltutorial-classic-usingplatforms" id="nxqltutorial-classic-usingplatforms"></a>

NXQLは3つのPlatformをサポートしています：Windows、Mac、およびMobileです。

* NXQLエディターを使用する場合、エディターの右上隅のチェックボックスをクリックして、クエリが適用されるプラットフォームを選択します。
* スクリプトやインテグレーションからのHTTPリクエストを介してAPIに直接クエリを行う場合は、導入部で説明されている**platform**パラメータを使用します。

複数のプラットフォームを選択する場合、選択したすべてのプラットフォームに共通であるテーブルとフィールドのみがクエリで有効であることに注意してください。 たとえば、デバイスの**name**フィールドは3つのプラットフォームすべてで使用可能ですが、**all\_antiviruses**はWindowsプラットフォームのデバイスのみで使用可能です。 したがって、フィールド**all\_antiviruses**を含むマルチプラットフォームクエリは無効です。

## 複数のテーブルの選択 <a href="#nxqltutorial-classic-selectingmultipletables" id="nxqltutorial-classic-selectingmultipletables"></a>

NXQLには複数のテーブルから情報を組み合わせることができる2種類のクエリがあります：

* 特定の種類のイベントに関連しているオブジェクトのユニークなペアを選択します。
* 特定の種類のイベント、およびそれらのイベントにリンクされたオブジェクトからの情報を選択します。

同じように見えるかもしれませんが、これらのクエリは以下で詳述するいくつかの側面で異なります。

複数のテーブルを要求する最も一般的なタイプのクエリは、一連のイベントに参加したオブジェクトのユニークなペアを選択することです。 このタイプのクエリでは、2つのオブジェクトテーブルのみを選択でき、**with**句内で各オブジェクトペアをリンクするイベントテーブルを指定します。 **select**句では、対応するフィールドリストの前にそれぞれのオブジェクトテーブルの名前を指定し、その後**from**句でオブジェクトテーブルの名前を繰り返します。 たとえば、**firefox.exe**を実行したユーザーとそれが実行されたデバイスの名前に興味がある場合は、次のクエリを記述します：

```
(select ((device name) (user name))
   (from (device user)
       (with execution
           (where binary
               (eq executable_name (pattern firefox.exe)))))
   (limit 100))
```

2番目の種類のクエリでは、選択されたイベントテーブルの個々のイベントが主な関心事であり、各イベントにリンクされたオブジェクトからの情報によってデコレートすることができます。 したがって、第2の種類のクエリを書くには、`from`句でイベントテーブルの名前と各追加オブジェクトテーブルの名前、および`select`句でそれらの対応するフィールドリストの前に指定します。 たとえば、次のクエリは、**firefox.exe**の最後の100接続、および各接続を開始したデバイスの名前を返します：

```
(select ((device (name))
         (connection (start_time end_time incoming_traffic outgoing_traffic)))
   (from (device connection)
       (where binary (eq executable_name (pattern firefox.exe))))
   (limit 100)
   (order_by start_time desc))
```

この2番目の種類のクエリでは、オブジェクトが複数のイベントにリンクされている場合、結果で繰り返される可能性があります。 たとえば、上記の例では、選択された接続の1つ以上にリンクされているデバイスが存在するかもしれません。 そのデバイスの名前は、関連する各接続のために繰り返し表示されます。 これは、ユニークなペアのオブジェクトを含む最初の種類のクエリとは逆であり、多くのイベントにリンクされているかもしれませんが、個々のイベントには興味がありません。

示された例にもかかわらず、第2の種類のクエリは2つのテーブルに限定されないことに気付いたかもしれません。 代わりに、1つのイベントテーブルと1つ以上のオブジェクトテーブルを選択する必要があります。 たとえば、今日行われた脅威レベルが設定されていないバイナリの実行をすべて取得し、バイナリパスとそれに関与しているバイナリ、デバイス、ユーザーについての情報を表示するには、次のように記述します：

```
(select 
    (
        (execution binary_path)
        (binary (executable_name version)) 
        (device (name last_ip_address))
        (user (name))
    )
    (from (execution binary device user) 
        (where binary (eq threat_level (enum "-")))
        (between midnight now)
    ) 
    (limit 100))
```

制約に関しては、両方のテーブルクエリには、返されるエントリーの最大数を制限するための**limit**句が必要であり、集計の計算を許可しません。

## クエリでパッケージを使用 <a href="#nxqltutorial-classic-usingpackagesinqueries" id="nxqltutorial-classic-usingpackagesinqueries"></a>

`package`は、オブジェクトテーブルまたは関連テーブルとして機能できるという意味で、NXQLにおける特別なキーワードです。 実際、パッケージはその属性（名前、バージョン、会社など）を持つインストール済みのパッケージ自体、またはそのインストールを通じたデバイスとの関係を指すことができます。 これは、通常イベントのみに使用される`with`句の中でパッケージを使用できる理由です。

たとえば、パッケージ**Microsoft Office 365**がインストールされているすべてのデバイスをリストするには、次のクエリを記述します（packageは関連として機能）：

```
(select (name)
   (from device
       (with package
           (where package (eq name (pattern "Microsoft Office 365 ProPlus*")))))
```

デバイスとともにパッケージバージョンを取得するには、次のクエリを記述します（`package`がオブジェクトとしても関連としても機能する）：

```
(select ((device (name)) (package (version name publisher)))
   (from (device package)
       (with package
            (where package
               (eq name (pattern "Microsoft Office 365 ProPlus*"))
               (eq type (enum program)))))
   (limit 10000))
```

単純に各デバイスにインストールされているパッケージの数を計算したい場合は、次のクエリを記述します（packageは関連として機能）：

```
(select (name)
   (from device
       (with package
           (compute number_of_packages)))
```

## オブジェクトのセットに対する操作 <a href="#nxqltutorial-classic-operationsonsetsofobjects" id="nxqltutorial-classic-operationsonsetsofobjects"></a>

NXQLを使用すると、同じタイプのオブジェクトの2つのリストを計算し、それらを1つのクエリで単一の結果に結合することができます。

たとえば、パッケージ**Microsoft Office**を持たないデバイスのリストを計算するには：

```
(select (name)
   (except
       (from device)   - すべてのデバイスのリスト
       (from device    - Officeを持つデバイスのリスト
           (with package
               (where package (eq name (pattern *Microsoft*Office*)))))))
```

上記のクエリを実行するために、システムはすべてのデバイスのリストを計算し、**Microsoft Office**を持つデバイスのリストを差し引くことで、**Microsoft Office**を持たないデバイスのリストを論理的に作成します。

3つのセット演算子が存在します：

* **except** (A) (B)\
  AにあるがBにないオブジェクトを返します。
* **union** (A) (B)\
  AまたはBにあるすべてのオブジェクトを返します。
* **intersect** (A) (B)\
  AとBの両方にあるオブジェクトのみを返します。

セット演算子でリンクされる2つの`from`句には1つのオブジェクトテーブルしか使用できないことを覚えておいてください。 たとえば、デバイスとユーザーのユニオンを行うことは不可能です。

これらの演算子はオブジェクトテーブルでのみ機能し、イベントテーブルでは機能しないことにも注意してください。

## カテゴリおよびカスタムフィールドの値を更新する <a href="#nxqltutorial-classic-updatingvaluesofcategoriesandcustomfields" id="nxqltutorial-classic-updatingvaluesofcategoriesandcustomfields"></a>

カテゴリ、つまり動的フィールドを更新するには、**update**ステートメントを使用します。 **update**ステートメントは、**from**句で選択されたすべてのオブジェクトに指定された動的フィールドの値を設定します。 たとえば、最後のIPアドレスに基づいて一部のデバイスの場所をパリに設定するには、次のクエリを記述します：

```
(update (set #Location (enum Paris))
   (from device
       (where device
           (eq last_ip_address (ip_network 172.16.12.0/16)))))
```

カテゴリの設定は、キーワードに関連する自動タグ付けルールをオーバーライドします。 自動タグ付けルールを再アクティブ化したい場合は、次のクエリを書いてください。

```
(update (set #Location nil)
   (from device
       (where device
           (eq last_ip_address (ip_network 172.16.12.0/16)))))
```

**update**ステートメントによって返されるテーブルには、すべての変更されたオブジェクトの識別子が含まれています。

## プレースホルダーの使用 <a href="#nxqltutorial-classic-usingplaceholders" id="nxqltutorial-classic-usingplaceholders"></a>

よく実行するクエリを一般化するには、プレースホルダーを使用します。 プレースホルダーは、値、カスタムフィールド名、またはクエリ内のカテゴリ名の代わりに使用する`%`キャラクターでプレフィックスされた数字です。 クエリが実行されると、各プレースホルダーはパラメータとして指定された実際の値に置き換えられます。 たとえば、次のクエリには2つのプレースホルダーが含まれています：

```
(select (id name)
   (from device
       (with web_request
           (where device (eq #%1 (enum %2)))
           (between midnight-1d midnight))))
```

このクエリを実行するには、デバイスのカスタムフィールドまたはカテゴリの名前とその実際の値をパラメーターとして提供する必要があります。 NXQLエディターでは、クエリの下にある2つのパラメーター入力のテキストボックスにパラメーター値を提供します。

プログラムされたクエリでは、HTTPリクエストで実際のパラメーターを提供します。
