with vs include
Note
Understanding the critical difference between with and include - when to filter objects by events vs. when to compute metrics for all objects.
Overview
with and include are both used to join event data to objects (like devices), but they behave very differently. Choosing the wrong one is one of the most common NQL mistakes.
Simple rule:
with= Filter to only objects that HAVE events → Reduces scopeinclude= Keep ALL objects, compute metrics from events → Full inventory with metrics
The Critical Difference
with - Filtering by Event Existence
When you use with, you're saying: "Show me only the objects that have these events"
Objects without matching events are excluded from results.
include - Computing Metrics for All Objects
When you use include, you're saying: "Show me all objects, and compute metrics from events where they exist"
Objects without events are kept in results (metrics show as null or 0).
Critical Concept
withchanges the set of objects you're working with (filtering)includedoes not change the set of objects (unless you usecompute)
Think of with as a WHERE clause and include as a LEFT JOIN
Comparison Table
| Feature | with | include |
|---|---|---|
| Objects without events | ❌ Excluded | ✅ Included |
| Scope modification | Yes - filters objects | No - unless compute used |
| Primary use case | Filtering by event conditions | Computing metrics for all objects |
compute requirement | Optional | Mandatory for effect |
| Example | "Devices that crashed" | "Crash count per device (including 0)" |
Syntax
/* with syntax - filters objects */
<table>
| with <event_table> during past Xd
/* include syntax - computes metrics */
<table>
| include <event_table> during past Xd
| compute metric = field.sum() # Required!
Real-World Examples
Example: Devices That Crashed (with)
Scenario: Find only the devices that have experienced crashes.
/* Returns ~15 devices (only those with crashes) */
devices
| with execution.crashes during past 7d
| list device.name
Result:
Explanation: Only devices with at least one crash are returned. If a device had no crashes, it's excluded entirely.
Example: Crash Count Per Device (include)
Scenario: Show crash count for ALL devices, including those with zero crashes.
/* Returns ~142 devices (all devices in inventory) */
devices
| include execution.crashes during past 7d
| compute crash_count = count()
| list device.name, crash_count
| sort crash_count desc
Result:
device.name crash_count
----------- -----------
LAPTOP-099 47
DESKTOP-042 23
LAPTOP-001 12
...
SERVER-100 0 # Devices with no crashes included!
LAPTOP-200 0
...
(142 devices total)
Explanation: All devices are shown. Devices without crashes display crash_count = 0.
When to Use Each
Use with When:
✅ Filtering for active objects - "Devices that executed this application" - "Users who accessed this website" - "Devices that connected to this server"
✅ Finding problematic objects - "Devices that crashed" - "Devices with failed connections" - "Devices that rebooted"
✅ You want to reduce scope - Only interested in objects that have the event - Don't care about objects without events
Examples:
/* Find devices running Outlook */
devices
| with execution.events during past 7d
| where binary.name = "outlook.exe"
| list device.name
/* Find devices with high connection failures */
devices
| with connection.events during past 7d
| where event.failed_connection_ratio >= 0.15
| list device.name
Use include When:
✅ Computing metrics for inventory - "CPU usage per device (all devices)" - "Crash count per device (including 0)" - "Average memory usage per device"
✅ Percentage calculations - "What % of devices have crashes?" - "Devices with low activity"
✅ Comparing active vs inactive - Need to see objects both with and without events - Identifying devices missing expected events
Examples:
/* CPU usage for all devices */
devices
| include device_performance.events during past 7d
| compute avg_cpu = cpu_usage.avg()
| list device.name, avg_cpu
| sort avg_cpu desc
/* Find devices NOT running expected software */
devices
| include execution.events during past 7d
| compute has_antivirus = binary.name.countif(binary.name = "antivirus.exe")
| where has_antivirus == 0 # Devices without the software
| list device.name
Common Patterns
Pattern 1: Filter Then Count (with)
/* How many devices executed Outlook? */
devices
| with execution.events during past 7d
| where binary.name = "outlook.exe"
| summarize device_count = count()
Pattern 2: Count Per Device (include)
/* Execution count per device for all devices */
devices
| include execution.events during past 7d
| compute execution_count = count()
| list device.name, execution_count
| sort execution_count desc
Pattern 3: Percentage of Total (include)
/* What percentage of devices crashed? */
devices
| include execution.crashes during past 7d
| compute has_crash = count()
| summarize
total_devices = count(),
devices_with_crashes = has_crash.countif(has_crash > 0),
crash_percentage = (has_crash.countif(has_crash > 0) * 100) / count()
Tips & Tricks
Test Both to Understand the Difference
Run the same query with with and include to see how results differ:
/* Version 1: with (filters) */
devices
| with execution.crashes during past 7d
| summarize device_count = count()
/* Might return: 15 devices */
/* Version 2: include (all devices) */
devices
| include execution.crashes during past 7d
| compute crash_count = count()
| summarize
total_devices = count(),
devices_with_crashes = crash_count.countif(crash_count > 0)
/* Returns: 142 total devices, 15 with crashes */
include Requires compute
Using include without compute doesn't do anything useful:
/* BAD - include without compute does nothing */
devices
| include execution.events during past 7d
| list device.name
/* Just returns all devices (events ignored) */
/* GOOD - include with compute */
devices
| include execution.events during past 7d
| compute execution_count = count()
| list device.name, execution_count
/* Returns all devices with their execution counts */
Common Mistake: Using with for Metrics
/* BAD - Excludes devices without events (incomplete picture) */
devices
| with device_performance.events during past 7d
| compute avg_cpu = cpu_usage.avg()
| list device.name, avg_cpu
/* Missing devices that had no performance data! */
/* GOOD - Shows all devices */
devices
| include device_performance.events during past 7d
| compute avg_cpu = cpu_usage.avg()
| list device.name, avg_cpu
/* Includes all devices, even those with no data (null) */
with Can Dramatically Change Results
/* Query 1: All devices in department */
devices
| where device.department = "IT"
| summarize device_count = count()
/* Returns: 50 devices */
/* Query 2: Only devices that executed something */
devices
| where device.department = "IT"
| with execution.events during past 7d
| summarize device_count = count()
/* Returns: 42 devices */
/* 8 devices in IT had no execution events (offline? new?) */
Decision Flowchart
Do you need ALL objects in results?
│
├─ YES → Use `include`
│ └─ Add `compute` to calculate metrics
│
└─ NO → Do you want to filter by event existence?
│
├─ YES → Use `with`
│ └─ Optionally add `compute` for metrics
│
└─ NO → Don't use event join at all
└─ Query the object table directly
Related Topics
- NQL Basics - Understanding core NQL concepts
- compute - Calculations - Per-object calculations
- where - Filtering Data - Filtering strategies
- Query Performance Guide - Performance implications of joins
Additional Resources
- Common Query Templates - Ready-to-use templates with
withandinclude - Field Reference - Available fields for different tables