# Azure Data Explorer

> Query and load data in Azure Data Explorer (Kusto): run read-only KQL queries with typed parameters, ingest rows inline or by streaming, write query results into tables, create and drop tables and stored functions, read schemas and table details, grant database roles, and check for failed ingestion. Works with the free cluster.

App · Databases · 20 actions. Web page: https://docs.lodol.com/docs/integrations/azure-data-explorer

## Actions

### Add database principal

Give a user, group or app a role on a database. Giving a role someone already holds changes nothing. Needs the app to be a database admin.

**Inputs**

- Principal (`principal`, text, required): A user's email, a group's email or object id, or an app's client id. A full name such as 'aaduser=ana@contoso.com' also works.
- Role (`role`, text, required): The role to give. One of: `admins`, `users`, `viewers`, `unrestrictedviewers` (Unrestricted viewers), `ingestors`, `monitors`.
- Principal type (`principal_type`, text): What kind of principal it is. One of: `aaduser` (User (email)), `aadgroup` (Group (email or object id)), `aadapp` (Application (client id)). Default: `aaduser`.
- Tenant (`tenant`, text): The principal's tenant id or domain, when it is not in the cluster's own tenant. Leave empty otherwise.
- Notes (`notes`, text): An optional note shown next to the role assignment.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `database` (text)
- `principal` (text)
- `principals` (list)
- `role` (text)

**Example output**

```json
{
  "database": "MyDatabase",
  "principal": "aaduser=ana@contoso.com",
  "principals": [],
  "role": "viewers"
}
```

### Clear table data

Delete every row in a table, including rows from streaming ingestion, but keep the table and its columns.

**Inputs**

- Table (`table`, text, required): The table. Names are case-sensitive.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `cleared` (true/false)
- `database` (text)
- `rows` (list)
- `table` (text)

**Example output**

```json
{
  "cleared": true,
  "database": "MyDatabase",
  "rows": [],
  "table": "Events"
}
```

### Create or alter function

Save a reusable KQL function, replacing any function of the same name. Other queries can then call it by name.

**Inputs**

- Function name (`function_name`, text, required): Letters, digits and underscores, starting with a letter.
- Body (`body`, text, required): The KQL the function runs, such as: Events | where Level == 'Error' | take maxRows
- Parameters (`parameters`, text): The function's parameters as name:type, comma-separated, such as 'maxRows:long'. Leave empty for none.
- Folder (`folder`, text): An optional folder to file the function under.
- Description (`doc_string`, text): An optional description stored with the function.
- Skip validation (`skip_validation`, true/false): Save the function even if it refers to tables that do not exist yet. Default: `false`.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `body` (text)
- `database` (text)
- `doc_string` (text)
- `folder` (text)
- `name` (text)
- `parameters` (text)

**Example output**

```json
{
  "body": "{ Events | where Level == 'Error' | take maxRows }",
  "database": "MyDatabase",
  "doc_string": "Latest error events",
  "folder": "Lodol",
  "name": "RecentErrors",
  "parameters": "(maxRows:long)"
}
```

### Create table

Create a table with the columns given. If a table of that name already exists with the same columns the step succeeds and changes nothing; with different columns it fails rather than pretend the table was created.

**Inputs**

- Table name (`table`, text, required): The new table's name. Names are case-sensitive.
- Columns (`columns`, list, required): Each column's name and type, in order. Text such as 'Timestamp:datetime, Level:string' also works.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).
- Folder (`folder`, text): An optional folder to file the table under.
- Description (`doc_string`, text): An optional description stored with the table.

**Outputs**

- `columns` (list): Each column's name and type
- `csl_schema` (text): The columns as name:type, comma-separated
- `database` (text)
- `doc_string` (text)
- `folder` (text)
- `schema` (object): The schema document as returned
- `schema_verified` (true/false): Whether the returned columns were checked against the request
- `table` (text)

**Example output**

```json
{
  "columns": [
    {
      "name": "Timestamp",
      "type": "datetime"
    },
    {
      "name": "Level",
      "type": "string"
    }
  ],
  "csl_schema": "Timestamp:datetime, Level:string",
  "database": "MyDatabase",
  "doc_string": "",
  "folder": "",
  "schema": {
    "Name": "Events",
    "OrderedColumns": [
      {
        "CslType": "datetime",
        "Name": "Timestamp",
        "Type": "System.DateTime"
      },
      {
        "CslType": "string",
        "Name": "Level",
        "Type": "System.String"
      }
    ]
  },
  "schema_verified": true,
  "table": "Events"
}
```

### Drop function

Delete a stored function.

**Inputs**

- Function (`function_name`, text, required): The stored function. Names are case-sensitive.
- Succeed if it is already gone (`if_exists`, true/false): When on, the step succeeds even if there is nothing to drop. Default: `true`.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `database` (text)
- `dropped` (true/false)
- `function_name` (text)

**Example output**

```json
{
  "database": "MyDatabase",
  "dropped": true,
  "function_name": "RecentErrors"
}
```

### Drop table

Delete a table. Its data can no longer be queried, though Azure keeps it recoverable for a while.

**Inputs**

- Table (`table`, text, required): The table. Names are case-sensitive.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).
- Succeed if it is already gone (`if_exists`, true/false): When on, the step succeeds even if there is nothing to drop. Default: `true`.

**Outputs**

- `database` (text)
- `dropped` (true/false)
- `remaining_tables` (list)
- `table` (text)

**Example output**

```json
{
  "database": "MyDatabase",
  "dropped": true,
  "remaining_tables": [
    "Logs"
  ],
  "table": "Events"
}
```

### Enable streaming ingestion

Turn streaming ingestion on (or off) for a table, which 'Stream rows into table' needs.

**Inputs**

- Table (`table`, text, required): The table. Names are case-sensitive.
- Enabled (`enabled`, true/false): On to allow streaming ingestion, off to stop it. Default: `true`.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `database` (text)
- `enabled` (true/false)
- `policy` (object)
- `rows` (list)
- `table` (text)

**Example output**

```json
{
  "database": "MyDatabase",
  "enabled": true,
  "policy": {
    "IsEnabled": true
  },
  "rows": [],
  "table": "Events"
}
```

### Get function

One stored function's parameters, body, folder and description.

**Inputs**

- Function (`function_name`, text, required): The stored function. Names are case-sensitive.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `body` (text)
- `database` (text)
- `doc_string` (text)
- `folder` (text)
- `name` (text)
- `parameters` (text)

**Example output**

```json
{
  "body": "{ Events | where Level == 'Error' | take maxRows }",
  "database": "MyDatabase",
  "doc_string": "Latest error events",
  "folder": "Lodol",
  "name": "RecentErrors",
  "parameters": "(maxRows:long)"
}
```

### Get table details

A table's row count, size and policies. The figures can be up to 15 minutes old, so to check rows you have just ingested, count them with 'Run query' instead.

**Inputs**

- Table (`table`, text, required): The table. Names are case-sensitive.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `AuthorizedPrincipals` (list)
- `CachingPolicy` (object)
- `DatabaseName` (text)
- `DocString` (text)
- `Folder` (text)
- `HotExtentSize` (number)
- `HotExtents` (number)
- `HotOriginalSize` (number)
- `HotRowCount` (number)
- `IngestionBatchingPolicy` (object)
- `MaxExtentsCreationTime` (text)
- `MergePolicy` (object)
- `MinExtentsCreationTime` (text)
- `RetentionPolicy` (object)
- `RowOrderPolicy` (text)
- `ShardingPolicy` (object)
- `StreamingIngestionPolicy` (object)
- `TableId` (text)
- `TableName` (text)
- `TotalExtentSize` (number)
- `TotalExtents` (number)
- `TotalOriginalSize` (number)
- `TotalRowCount` (number)

**Example output**

```json
{
  "DatabaseName": "MyDatabase",
  "StreamingIngestionPolicy": {
    "IsEnabled": true
  },
  "TableName": "Events",
  "TotalExtentSize": 40960.0,
  "TotalExtents": 3,
  "TotalRowCount": 1200
}
```

### Get table schema

A table's columns and their types.

**Inputs**

- Table (`table`, text, required): The table. Names are case-sensitive.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `columns` (list): Each column's name and type
- `csl_schema` (text): The columns as name:type, comma-separated
- `database` (text)
- `doc_string` (text)
- `folder` (text)
- `schema` (object): The schema document as returned
- `table` (text)

**Example output**

```json
{
  "columns": [
    {
      "name": "Timestamp",
      "type": "datetime"
    },
    {
      "name": "Level",
      "type": "string"
    }
  ],
  "csl_schema": "Timestamp:datetime, Level:string",
  "database": "MyDatabase",
  "doc_string": "",
  "folder": "",
  "schema": {
    "Name": "Events",
    "OrderedColumns": [
      {
        "CslType": "datetime",
        "Name": "Timestamp",
        "Type": "System.DateTime"
      },
      {
        "CslType": "string",
        "Name": "Level",
        "Type": "System.String"
      }
    ]
  },
  "table": "Events"
}
```

### Ingest inline data

Add rows to a table straight away, sending them inside the request. Suited to the small batches a workflow produces (up to 1 MB per step) and needs no streaming policy.

**Inputs**

- Table (`table`, text, required): The table. Names are case-sensitive.
- Data (`data`, text): The rows as text in the chosen format, one record per line, with one value per table column in the table's column order. Use this or 'Rows'.
- Rows (`rows`, list): The rows as a list, each either a list of values in column order or an object of column: value. Sent as CSV. Use this or 'Data'.
- Format (`data_format`, text): The format of 'Data'. Rows given as a list are always CSV. One of: `csv`, `tsv` (TSV (tab-separated)), `psv` (PSV (pipe-separated)), `json` (JSON (needs a mapping)), `multijson` (Multi-line JSON (needs a mapping)). Default: `csv`.
- Ingestion mapping (`mapping_name`, text): The name of an ingestion mapping created on the table. Required for JSON formats; leave empty for CSV, TSV and PSV.
- Skip header line (`ignore_first_record`, true/false): Turn on when the first line of 'Data' is a header. Default: `false`.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `database` (text)
- `extent_ids` (list)
- `format` (text)
- `rows_sent` (number)
- `table` (text)

**Example output**

```json
{
  "database": "MyDatabase",
  "extent_ids": [
    "4a6d9b1e-6f2c-4b4e-9f52-0d3c9a1b2c3d"
  ],
  "format": "csv",
  "rows_sent": 2,
  "table": "Events"
}
```

### List database principals

Which users, groups and apps hold which role on a database. Needs the app to be a database admin.

**Inputs**

- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `columns` (list): The result's columns, in order
- `database` (text): The database it ran against
- `row_count` (number): How many rows are returned
- `rows` (list): The rows, each keyed by column name
- `truncated` (true/false): Whether more rows existed than were returned

**Example output**

```json
{
  "columns": [
    {
      "name": "Role",
      "type": "string"
    }
  ],
  "database": "MyDatabase",
  "row_count": 1,
  "rows": [
    {
      "Notes": "Lodol",
      "PrincipalDisplayName": "Lodol",
      "PrincipalFQN": "aadapp=00000000-0000-0000-0000-000000000000",
      "PrincipalObjectId": "00000000-0000-0000-0000-000000000000",
      "PrincipalType": "AAD Application",
      "Role": "Database MyDatabase Admin"
    }
  ],
  "truncated": false
}
```

### List databases

The databases the app can see. A database only appears once the app has been given a role on it.

**Inputs**: None.

**Outputs**

- `columns` (list): The result's columns, in order
- `database` (text): The database it ran against
- `databases` (list): The database names
- `hint` (text): What to do when none are visible
- `row_count` (number): How many rows are returned
- `rows` (list): The rows, each keyed by column name
- `truncated` (true/false): Whether more rows existed than were returned

**Example output**

```json
{
  "columns": [
    {
      "name": "DatabaseName",
      "type": "string"
    }
  ],
  "database": null,
  "databases": [
    "MyDatabase"
  ],
  "row_count": 1,
  "rows": [
    {
      "DatabaseName": "MyDatabase",
      "PrettyName": "MyDatabase"
    }
  ],
  "truncated": false
}
```

### List functions

The stored functions in a database, with their parameters and body.

**Inputs**

- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `columns` (list): The result's columns, in order
- `database` (text): The database it ran against
- `functions` (list): The function names
- `row_count` (number): How many rows are returned
- `rows` (list): The rows, each keyed by column name
- `truncated` (true/false): Whether more rows existed than were returned

**Example output**

```json
{
  "columns": [
    {
      "name": "Name",
      "type": "string"
    }
  ],
  "database": "MyDatabase",
  "functions": [
    "RecentErrors"
  ],
  "row_count": 1,
  "rows": [
    {
      "Name": "RecentErrors",
      "Parameters": "(maxRows:long)"
    }
  ],
  "truncated": false
}
```

### List ingestion failures

Ingestion that failed in the last 14 days, with the table, time, error and whether it is worth retrying.

**Inputs**

- Table (`table`, text): Only failures for this table. Leave empty for all.
- Maximum rows (`limit`, number): Return at most this many failures. From 1 to 10000. Default: `100`.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `columns` (list): The result's columns, in order
- `database` (text): The database it ran against
- `row_count` (number): How many rows are returned
- `rows` (list): The rows, each keyed by column name
- `truncated` (true/false): Whether more rows existed than were returned

**Example output**

```json
{
  "columns": [
    {
      "name": "Table",
      "type": "string"
    }
  ],
  "database": "MyDatabase",
  "row_count": 0,
  "rows": [],
  "truncated": false
}
```

### List tables

The tables in a database, with their folder and description.

**Inputs**

- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `columns` (list): The result's columns, in order
- `database` (text): The database it ran against
- `row_count` (number): How many rows are returned
- `rows` (list): The rows, each keyed by column name
- `tables` (list): The table names
- `truncated` (true/false): Whether more rows existed than were returned

**Example output**

```json
{
  "columns": [
    {
      "name": "TableName",
      "type": "string"
    }
  ],
  "database": "MyDatabase",
  "row_count": 1,
  "rows": [
    {
      "DatabaseName": "MyDatabase",
      "TableName": "Events"
    }
  ],
  "tables": [
    "Events"
  ],
  "truncated": false
}
```

### Run management command

Run any management command (text starting with '.', such as '.show table Events extents') for anything the other actions do not cover. What it may do is limited by the app's database role.

**Inputs**

- Command (`command`, text, required): The command, starting with '.'.
- Database (`database`, text): The database to run it in. Leave empty for the connection's default, or for a cluster-level command such as '.show databases'.
- Maximum rows (`limit`, number): Return at most this many rows. From 1 to 10000. Default: `1000`.

**Outputs**

- `columns` (list): The result's columns, in order
- `database` (text): The database it ran against
- `row_count` (number): How many rows are returned
- `rows` (list): The rows, each keyed by column name
- `table_count` (number): How many result tables
- `truncated` (true/false): Whether more rows existed than were returned

**Example output**

```json
{
  "columns": [
    {
      "name": "Timestamp",
      "type": "datetime"
    },
    {
      "name": "Level",
      "type": "string"
    }
  ],
  "database": "MyDatabase",
  "row_count": 1,
  "rows": [
    {
      "Level": "Info",
      "Timestamp": "2026-09-22T10:00:00Z"
    }
  ],
  "table_count": 1,
  "truncated": false
}
```

### Run query

Run a KQL query and return its rows. The query runs read-only, so it cannot change data. Put values in 'Query parameters' and refer to them by name, so a quote in a value cannot change the query.

**Inputs**

- KQL query (`query`, text, required): The query, such as: Events | where Level == lvl | take 10
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).
- Query parameters (`parameters`, object): Values the query refers to by name, such as {"lvl": "Error"}. Text, whole numbers, decimals, true/false and JSON values are typed automatically.
- Maximum rows (`limit`, number): Return at most this many rows. From 1 to 10000. Default: `1000`.

**Outputs**

- `columns` (list): The result's columns, in order
- `database` (text): The database it ran against
- `errors` (list): Errors reported by the query
- `has_errors` (true/false): Whether the query reported errors alongside its rows
- `row_count` (number): How many rows are returned
- `rows` (list): The rows, each keyed by column name
- `table_count` (number): How many result tables
- `truncated` (true/false): Whether more rows existed than were returned

**Example output**

```json
{
  "columns": [
    {
      "name": "Timestamp",
      "type": "datetime"
    },
    {
      "name": "Level",
      "type": "string"
    }
  ],
  "database": "MyDatabase",
  "errors": [],
  "has_errors": false,
  "row_count": 1,
  "rows": [
    {
      "Level": "Info",
      "Timestamp": "2026-09-22T10:00:00Z"
    }
  ],
  "table_count": 1,
  "truncated": false
}
```

### Stream rows into table

Send rows through streaming ingestion, which makes them queryable within seconds. The table needs streaming ingestion turned on first ('Enable streaming ingestion'); 'Ingest inline data' works without it.

**Inputs**

- Table (`table`, text, required): The table. Names are case-sensitive.
- Data (`data`, text): The rows as text in the chosen format, one record per line, with one value per table column in the table's column order. Use this or 'Rows'.
- Rows (`rows`, list): The rows as a list, each either a list of values in column order or an object of column: value. Sent as CSV. Use this or 'Data'.
- Format (`stream_format`, text): The format of 'Data'. Rows given as a list are always CSV. One of: `CSV`, `TSV` (TSV (tab-separated)), `PSV` (PSV (pipe-separated)), `JSON` (JSON (needs a mapping)), `MultiJSON` (Multi-line JSON (needs a mapping)). Default: `CSV`.
- Ingestion mapping (`mapping_name`, text): The name of an ingestion mapping created on the table. Required for JSON formats; leave empty for CSV, TSV and PSV.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `accepted` (true/false)
- `database` (text)
- `details` (list)
- `format` (text)
- `rows_sent` (number)
- `table` (text)

**Example output**

```json
{
  "accepted": true,
  "database": "MyDatabase",
  "details": [],
  "format": "CSV",
  "rows_sent": 2,
  "table": "Events"
}
```

### Write query results to table

Run a query and write its rows into a table: appending, replacing, or creating the table. Columns are matched by type and position, not by name, so project them in the table's order.

**Inputs**

- Target table (`table`, text, required): The table to write into.
- KQL query (`query`, text, required): The query whose rows are written.
- Mode (`mode`, text): Whether to append, replace or create. One of: `set-or-append` (Append, creating the table if needed), `append` (Append to an existing table), `set-or-replace` (Replace the table's data, creating it if needed), `set` (Create a new table (fails if it exists)). Default: `set-or-append`.
- Add new columns (`extend_schema`, true/false): Add columns the query has and the table lacks, instead of failing. Default: `false`.
- Database (`database`, text): The database to use. Leave empty for the connection's default database (or the only database the app can see).

**Outputs**

- `database` (text)
- `extents` (list)
- `mode` (text)
- `rows_ingested` (number)
- `table` (text)

**Example output**

```json
{
  "database": "MyDatabase",
  "extents": [
    {
      "ExtentId": "4a6d9b1e-6f2c-4b4e-9f52-0d3c9a1b2c3d"
    }
  ],
  "mode": "set-or-append",
  "rows_ingested": 2,
  "table": "Events"
}
```
