Multiple query results

Multiple query results

The query workspace displays a separate result tab for each executable statement. Statements execute sequentially in script order. Rows appear while the current statement runs. A let declaration defines a reusable expression and does not create a result tab.

let events = MyTable | where Timestamp > ago(1h);
events | take 100;
events | count;

Each result has its own columns and chart hint. Select a result tab to inspect its rows or chart. Charts become available when their result completes. Cancelling or encountering an error preserves received rows and marks unfinished results as partial. Export filenames identify partial results.

Streaming API

Send Accept: application/x-ndjson to POST /search/{accountId}/kusto to receive newline-delimited JSON. The request body and authentication are unchanged. Requests without this header retain the existing single-result JSON response.

EventFieldsMeaning
resultStartresultId, header, columns, optional render, sourceStart, sourceLengthCreate a result with its own schema; source offsets refer to the submitted script.
rowsresultId, rowsAppend positional row arrays matching the result's ordered columns.
messageresultId, timestamp, messageExecution diagnostic.
resultCompleteresultId, rowCountThe result completed successfully, including empty results.
queryComplete—All statements completed successfully.
queryErroroptional resultId, messageTerminal execution failure. Received rows remain partial.

Result IDs start at zero and increase in script order. Do not assume that network chunks align with JSON lines or UTF-8 characters. A connection ending without queryComplete or queryError is interrupted, not successful.

Validation and permission errors before streaming use the existing HTTP error response. Once streaming starts, errors use queryError rather than changing the HTTP status. The schema is flushed immediately; pending rows are flushed at approximately 64 KiB, 4,096 rows, or 100 ms while waiting for more executor output. Operators that need all their input, such as sorting, may delay the first row.

Each statement uses the existing bounded executor and memory/spill admission. The script shares cancellation and the caller's maximum timeout. Completed pipelines release resources before the next statement starts. Streaming avoids waiting for a complete JSON document, but the workspace still retains received rows in browser memory.

Deploy updated executor nodes before enabling the streaming workspace on query hosts: the additive executor request field selects an explicit output stream, including the command output stream. Existing executor requests remain compatible.

Statement permission checks run for the whole script before execution begins. Each statement then selects its current files and executor after the previous statement has finished and released its resources. For example, .truncate table 'logs'; logs | count counts the table after truncation. Statement plans include only their own work and referenced let declarations; bindings remain lazy query expressions rather than materialized results.

After cancellation or failure, completed results remain complete and unfinished results are marked partial. Data, charts, copy, and export remain available for the selected retained result, including an empty result. Exports contain only the rows received so far; the error and partial status remain visible.