sort - Ordering Results
Note
The sort clause orders query results in ascending (lowest first) or descending (highest first) order - essential for Top N queries and trend analysis.
Overview
The sort clause controls the order of rows in your query results. It's typically used after aggregations to show top/bottom values or to display time-series data chronologically.
Common uses:
- Top N queries - Show highest/lowest values
- Time-series - Display trends chronologically
- Alphabetical lists - Sort names A-Z or Z-A
- Dashboard rankings - Order by importance
Basic Syntax
/* Ascending order (lowest to highest) */
| sort <field_name> asc
/* Descending order (highest to lowest) */
| sort <field_name> desc
Direction is Required
You must specify asc or desc - it's not optional!
Sort Directions
asc - Ascending (Lowest to Highest)
For numbers: Smallest to largest For text: A to Z alphabetically For dates: Oldest to newest
Output:
desc - Descending (Highest to Lowest)
For numbers: Largest to smallest For text: Z to A (reverse alphabetical) For dates: Newest to oldest
Output:
Common Use Cases
Use Case 1: Top N Pattern (Highest Values)
The most common use of sort - finding top performers/offenders.
/* Top 20 devices by CPU usage */
execution.events during past 7d
| summarize avg_cpu = cpu_time.avg() by device.name
| sort avg_cpu desc # Highest CPU first
| limit 20
Use Case 2: Bottom N Pattern (Lowest Values)
Finding lowest values - useful for disk space, performance issues.
/* Devices with least disk space */
devices during past 7d
| include device_performance.events
| compute free_space = free_disk_space.last()
| sort free_space asc # Lowest space first
| limit 20
Use Case 3: Alphabetical Sorting
Organizing names alphabetically.
/* Alphabetical device list */
devices
| list device.name, operating_system.name
| sort device.name asc # A to Z
Use Case 4: Time-Series (Chronological)
CRITICAL for time-series: Always sort by start_time asc for trends.
/* Daily crash trend (chronological) */
execution.crashes during past 7d
| summarize crash_count = count() by 1d
| sort start_time asc # Oldest to newest (chronological)
Sorting Different Field Types
Numeric Fields
/* Sort by memory size */
devices
| list device.name, device.hardware.memory
| sort device.hardware.memory desc # Largest memory first
Text Fields
/* Sort by OS name */
devices
| list device.name, operating_system.name
| sort operating_system.name asc # Alphabetical
Aggregated Values
/* Sort by calculated metric */
web.page_views during past 7d
| where application.name == "Confluence"
| summarize avg_load_time = page_load_time.backend.avg() by device.name
| list device.name, avg_load_time
| sort avg_load_time desc # Slowest devices first
Computed Metrics
/* Sort by computed value */
devices during past 7d
| include execution.events
| compute avg_cpu = cpu_time.avg()
| list device.name, avg_cpu
| sort avg_cpu desc # Highest CPU first
Real-World Examples
Example: Top 10 Largest Binaries
Scenario: Find the largest executable files.
Example: Crash Trend (Chronological)
Scenario: Display daily crash trend for charting.
execution.crashes during past 30d
| where binary.binary.name == "outlook.exe"
| summarize crash_count = count() by 1d
| sort start_time asc # Chronological for line chart
Why asc: Charts display left-to-right (oldest to newest)
Example: Devices Needing Attention
Scenario: Find devices with lowest disk space (most urgent).
Example: Application Crash Leaderboard
Scenario: Show which applications crash the most.
Sort Position in Query
sort typically comes after filtering and aggregation, before limit:
/* Standard order */
devices during past 7d
| where operating_system.platform == windows # Filter
| include execution.events
| compute avg_cpu = cpu_time.avg() # Compute
| where avg_cpu > 50 # Filter computed
| list device.name, avg_cpu # Select fields
| sort avg_cpu desc # Order results
| limit 20 # Restrict rows
Common Patterns
Pattern: Top N by Metric
Pattern: Bottom N by Metric
Pattern: Chronological Time-Series
<event_table> during past Xd
| summarize metric = field.agg() by 1d
| sort start_time asc # Always asc for chronological
Pattern: Alphabetical List
Tips & Tricks
Always Sort Time-Series by start_time asc
For trends and charts, always sort chronologically:
Sort After Aggregation, Not Before
Sorting individual events before aggregation is meaningless:
/* ❌ WRONG - Sorting events before aggregation */
execution.events during past 7d
| sort cpu_time desc # Meaningless on individual events
| summarize avg_cpu = cpu_time.avg() by device.name
/* ✅ CORRECT - Sort aggregated results */
execution.events during past 7d
| summarize avg_cpu = cpu_time.avg() by device.name
| sort avg_cpu desc # Sort the aggregated values
Combine with limit for Top/Bottom N
Field Doesn't Need to Be in list
You can sort by a field that's not displayed (though it's clearer to include it):
Common Mistake: Missing Direction
Common Mistake: Wrong Order for Time-Series
/* ❌ WRONG - Descending shows newest first (backwards chart) */
execution.crashes during past 7d
| summarize count = count() by 1d
| sort start_time desc # Chart will be backwards!
/* ✅ CORRECT - Ascending for chronological charts */
execution.crashes during past 7d
| summarize count = count() by 1d
| sort start_time asc # Proper chronological order
Performance Considerations
sort has minimal performance impact - it's applied to the result set after all data processing.
Best practices:
- Sort doesn't reduce query cost (filtering does)
- Position doesn't matter much (applied to final results)
- Common pattern: filter → compute/summarize → sort → limit
Related Topics
- limit - Restricting Rows - Combine with sort for Top N queries
- summarize - Aggregations - Often sort after aggregating
- list - Selecting Fields - Choose which fields to display
- where - Filtering Data - Filter before sorting
Additional Resources
- NQL Syntax Cheat Sheet - Quick sort reference
- Common Query Templates - Templates using sort patterns