# ES|QL Syntax Guide

This guide provides an overview of the ES|QL syntax and examples of its usage.

## Basic Syntax

An ES|QL query is composed of a source command followed by an optional series of processing commands, separated by a pipe character (`|`). For example:

```esql
source-command
| processing-command1
| processing-command2
```

The result of a query is the table produced by the final processing command.

For readability, each processing command is typically written on a new line. However, an ES|QL query can also be written as a single line:

```esql
source-command | processing-command1 | processing-command2
```

## Identifiers

Identifiers in ES|QL need to be quoted with backticks (```) if they don’t start with a letter, `_` or `@`, or if any of the other characters is not a letter, number, or `_`.

For example:

```esql
FROM index
| KEEP `1.field`
```

When referencing a function alias that itself uses a quoted identifier, the backticks of the quoted identifier need to be escaped with another backtick.

For example:

```esql
FROM index
| STATS COUNT(`1.field`)
| EVAL my_count = `COUNT(``1.field``)`
```

## Literals

ES|QL currently supports numeric, string and timespan literals.

### String Literals

A string literal is a sequence of unicode characters delimited by double quotes (`"`). For example:

```esql
FROM index
| WHERE first_name == "Georgi"
```

If the literal string itself contains quotes, these need to be escaped (`\\"`). ES|QL also supports the triple-quotes (`"""`) delimiter, for convenience:

```esql
ROW name = """Indiana "Indy" Jones"""
```

The special characters CR, LF and TAB can be provided with the usual escaping: `\r`, `\n`, `\t`, respectively.

### Numerical Literals

The numeric literals are accepted in decimal and in the scientific notation with the exponent marker (`e` or `E`), starting either with a digit, decimal point `.` or the negative sign `-`.

For example:

- `1969`    -- integer notation
- `3.14`    -- decimal notation
- `.1234`   -- decimal notation starting with decimal point
- `4E5`     -- scientific notation (with exponent marker)
- `1.2e-3`  -- scientific notation with decimal point
- `-.1e2`   -- scientific notation starting with the negative sign

The integer numeric literals are implicitly converted to the `integer`, `long` or the `double` type, whichever can first accommodate the literal’s value.

## Timespan Literals

Datetime intervals and timespans can be expressed using timespan literals. Timespan literals are a combination of a number and a qualifier.

These qualifiers are supported:

- `millisecond`/`milliseconds`/`ms`
- `second`/`seconds`/`sec`/`s`
- `minute`/`minutes`/`min`
- `hour`/`hours`/`h`
- `day`/`days`/`d`
- `week`/`weeks`/`w`
- `month`/`months`/`mo`
- `quarter`/`quarters`/`q`
- `year`/`years`/`yr`/`y`

Timespan literals are not whitespace sensitive, and should not be wrapped with quotes:
- GOOD: 1day
- GOOD: 1 day
- BAD: "day"
- BAD: "2 days"

## Example Queries with Timespan Literals

Here are some example queries that use timespan literals:

1. Retrieve logs from the last 24 hours and calculate the average response time:

```esql
FROM logs-*
| WHERE @timestamp > NOW() - 24h
| STATS avg_response_time = AVG(response_time)
```

2. Get the count of events per day for the last 7 days:

```esql
FROM events
| WHERE @timestamp > NOW() - 7 days
| STATS daily_count = COUNT(*) BY day = DATE_TRUNC(1 day, @timestamp)
| SORT day
```

3. Find the maximum temperature recorded in the last month:

```esql
FROM weather_data
| WHERE @timestamp > NOW() - 1 month
| STATS max_temp = MAX(temperature)
```

4. Calculate the total sales for each week in the last quarter:

```esql
FROM sales
| WHERE @timestamp > NOW() - 1 quarter
| STATS weekly_sales = SUM(sales_amount) BY week = DATE_TRUNC(1 week, @timestamp)
| SORT week
```

4. The same example with BUCKET instead of DATE_TRUNC:

```esql
FROM sales
| WHERE @timestamp > NOW() - 1 quarter
| STATS weekly_sales = SUM(sales_amount) BY week = BUCKET(@timestamp, 1 week)
| SORT week
```

5. Retrieve error logs from the last 15 minutes and group by error type:

```esql
FROM error_logs
| WHERE @timestamp > NOW() - 15 minutes
| STATS error_count = COUNT(*) BY error_type
| SORT error_count DESC
```

#### Comments

ES|QL uses C++ style comments:
- Double slash `//` for single line comments
- `/*` and `*/` for block comments

```esql
// Query the employees index
FROM employees
| WHERE height > 2
```

```esql
FROM /* Query the employees index */ employees
| WHERE height > 2
```

```esql
FROM employees
/* Query the
 * employees
 * index */
| WHERE height > 2
```
