> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kinetica.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Queries (SQL)

```sql title="SELECT Statement Syntax" theme={null}
SELECT [DISTINCT | TOP <n>]
    <column expression> [EXCLUDE(<column exclusion list>)],...
FROM [<schema name>.]<table name> [<table alias>]
    [<join type> JOIN <join table name> [<join alias>] ON <join expr>],...
[WHERE <filtering expression list>]
[GROUP BY <grouping expression list>]
[HAVING <group filtering expression list>]
[ORDER BY <ordering expression list>]
[LIMIT [<offset>, ]<num rows>]
```

<Info>
  * In any *column expression*, a wildcard like `*` can be used to specify
    all columns, while `<table name/alias>.*` can be used to specify all
    columns from the given table.

  * The `EXCLUDE` function can be used to list columns to exclude from the
    wildcard expression it follows; for instance, the following can be
    used to select all columns from the employee table except for the `ssn`
    & `date_of_birth` columns:

    ```sql title="EXCLUDE Example" theme={null}
    SELECT e.* EXCLUDE(ssn, date_of_birth)
    FROM employee e
    ```

  * Table & column names can be double-quoted to use reserved words, e.g.,
    `"PERCENT"`; or to use numbers or special characters in column names,
    e.g., `"1234"` or `"key:value"`.

  * `TOP <n>` returns the first *n* records (up to *20000* records by
    default).

  * The *grouping expression list* may contain column names, aliases,
    expressions, or positions (e.g., `GROUP BY 2` to aggregate on the 2nd
    column in the `SELECT` list).

  * The *having expression list* may contain grouping expressions or any
    grouping expression aliases defined in the `SELECT` list.

  * The *ordering expression list* may contain column names, expressions, or
    column positions (e.g., `ORDER BY 2` to aggregate on the 2nd column in
    the `SELECT` list).  The default ordering is `ASC`.  The default null
    ordering is `NULLS FIRST` when using ascending order and `NULLS LAST`
    when using descending order.  The general format for each
    comma-separated ordering expression in the list is:

    ```sql title="ORDER BY Expression Syntax" theme={null}
    <column name/alias/expression/position> [ASC | DESC] [NULLS FIRST | NULLS LAST]
    ```

  * `LIMIT` applies paging to the result set, starting at the 0-based
    *offset* (if specified) and returning *num rows* records.
</Info>

```sql SELECT Example theme={null}
SELECT
    e.last_name || ', ' || e.first_name AS "Employee_Name",
    m.last_name || ', ' || m.first_name AS "Manager_Name"
FROM
    example.employee e
    LEFT JOIN example.employee m ON e.manager_id = m.id
WHERE
    e.dept_id IN (1, 2, 3)
ORDER BY
    m.id ASC NULLS FIRST,
    e.hire_date
```

<a id="sql-tableless-query" />

## Tableless Query

A query without a `FROM` clause can be used to return a single row of data
containing a constant or expression.

For example, to select the current day of the week:

```sql Tableless Query Example theme={null}
SELECT DAYNAME(NOW()) AS "Today"
```

<Info>
  A *tableless query* will create a result set backed by a
  [replicated](/content/concepts/tables#replicated) table, by default.
</Info>

<a id="sql-join" />

## Join

The supported *join types* are:

* `INNER JOIN` - matching rows between two tables
* `[LEFT] SEMI JOIN` - rows in the left-hand table that have matching rows in
  the right-hand table
* `LEFT [OUTER] JOIN` - matching rows between two tables, and rows in the
  left-hand table that have no matching rows in the right-hand table
* `RIGHT [OUTER] JOIN` - matching rows between two tables, and rows in the
  right-hand table that have no matching rows in the left-hand table
* `FULL [OUTER] JOIN` matching rows between two tables, and rows in both
  tables that have no matching rows in the other
* `CROSS JOIN` - every row in one table paired with every row in the other

There are two execution schemes that are used to process *joins*, depending on
the [distribution](/content/concepts/tables#distribution) of the joined tables:

* [Local](/content/concepts/joins#join-local) - highly performant, but native
  [join criteria](/content/concepts/joins) must be met
* [Distributed](/content/concepts/joins#join-distributed) - highly flexible, as native *join*
  restrictions are lifted, but less performant due to interprocessor
  communication overhead and requires more memory & disk space to process

<Note>
  Though the data distribution restrictions on native
  [joins](/content/concepts/joins) do not exist for *joins* made via SQL,
  following the *join* guidelines on [sharding](/content/concepts/tables#sharding) will result in
  much more performant queries.
</Note>

*Kinetica* supports both `JOIN ... ON` and `WHERE` clause syntax for
*inner joins*;  all *outer join* types (`LEFT`, `RIGHT`, & `FULL OUTER`)
require `JOIN ... ON` syntax.

For example, to list the name of each employee and the name of the employee's
manager, using the `WHERE` clause to specify the *join* condition:

```sql JOIN via WHERE Clause Example theme={null}
SELECT
    e.last_name || ', ' || e.first_name AS "Employee_Name",
    m.last_name || ', ' || m.first_name AS "Manager_Name"
FROM
    example.employee e,
    example.employee m
WHERE
    e.manager_id = m.id
ORDER BY
    e.last_name,
    e.first_name
```

To list the name of each employee and the associated manager, even for employees
that don't have a manager, using the `JOIN ... ON` syntax to specify the
*join* condition:

```sql JOIN via FROM Clause Example theme={null}
SELECT
    e.last_name || ', ' || e.first_name AS "Employee_Name",
    m.last_name || ', ' || m.first_name AS "Manager_Name"
FROM
    example.employee e
    LEFT JOIN example.employee m ON e.manager_id = m.id
ORDER BY
    e.last_name,
    e.first_name
```

<a id="sql-join-asof" />

<a id="sql-join-asof" />

### ASOF

*Kinetica* supports the notion of an inexact match *join* via the `ASOF`
*join* function.  This feature allows each left-side table record to be matched
to a single right-side table record whose join column value is the smallest or
largest value within a range relative to the left-side join column value.  In
the case where multiple right-side table records have the same smallest or
largest value for a given left-side table record, only one of the right-side
table records will be chosen (non-deterministically) and returned as part of the
*join*.

```sql title="ASOF Syntax" theme={null}
ASOF(<left_column>, <right_column>, <rel_range_begin>, <rel_range_end>, <MIN|MAX>)
```

The five parameters are:

* `left_column` - name of the column to join on from the left-side table
* `right_column` - name of the column to join on from the right-side table
* `rel_range_begin` - constant value defining the position, relative to each
  left-side column value, of the beginning of the range in which to match
  right-side column values; use a negative constant to begin the range before
  the left-side column value, or a positive one to begin after it
* `rel_range_end` - constant value defining the position, relative to each
  left-side column value, of the end of the range in which to match right-side
  column values; use a negative constant to end the range before the left-side
  column value, or a positive one to end after it
* `MIN|MAX` - use `MIN` to return the right-side matched record with the
  smallest join column value; use `MAX` to return the right-side matched
  record with the greatest join column value

Effectively, each matched right-side column value must be:

* `>=` *\<left-side column value>* `+ rel_range_begin`
* `<=` *\<left-side column value>* `+ rel_range_end`

<Note>
  `ASOF` *joins* are unsupported on some *materialized views*.
  In these situations, the materialized view can be recreated with the
  `KI_HINT_PROJECT_MATERIALIZED_VIEW` hint to allow it to be used in an
  `ASOF` join.
</Note>

#### Examples

The following `ASOF` call might be used to list, for each flight arrival time,
the soonest flight departure time that occurs between half an hour and an hour
and a half after the arrival; effectively, the time-matching portion of a
connecting flight query:

```sql ASOF Time-Based Expression Example theme={null}
ASOF(inbound.eta, outbound.etd, INTERVAL '30' MINUTE, INTERVAL '90' MINUTE, MIN)
```

This `ASOF` call returns right-side locations that are nearest eastward to
each left-side location, for locations within 5 degrees of the left-side:

```sql ASOF Distance-Based Expression Example theme={null}
ASOF(b.x, n.x, .00001, 5, MIN)
```

For example, to match a set of stock trades to the opening prices for those
stocks (if an opening price record exists within 24 hours prior to the trade),
and to include trades for which there is no opening stock price record:

```sql ASOF JOIN Example theme={null}
SELECT
    t.id,
    t.dt AS execution_dt,
    q.open_dt AS quote_dt,
    t.price AS execution_price,
    q.open_price
FROM
    example.trades t
    LEFT JOIN example.quotes q ON
        t.ticker = q.symbol AND
        ASOF(t.dt, q.open_dt, INTERVAL '-1' DAY, INTERVAL '0' DAY, MAX)
```

While the `ASOF` *join* function can only be used as part of a *join*, it can
effectively be made into a filter condition by sub-selecting the filter criteria
in the `FROM` clause and joining on that criteria.

For instance, to look up the stock price for a given company as of a given date:

```sql ASOF JOIN with Filter Example theme={null}
SELECT
    t.ticker,
    t.asof_dt,
    q.open_dt,
    q.open_price
FROM
    (SELECT 'EBAY' AS ticker, DATETIME('2006-12-15 12:34:56') AS asof_dt) t
    LEFT JOIN example.quotes q ON
        t.ticker = q.symbol AND
        ASOF(t.asof_dt, q.open_dt, INTERVAL '-1' DAY, INTERVAL '0' DAY, MAX)
```

<a id="sql-aggregation" />

<a id="sql-aggregation" />

## Aggregation

The `GROUP BY` clause can be used to segment data into groups and apply
[aggregate functions](/content/sql/query#sql-aggregation-functions) over the values within
each group.  Aggregation functions applied to data without a `GROUP BY` clause
will be applied over the entire result set.

<Info>
  `GROUP BY` can operate on columns, column expressions, column
  aliases, or the position of a member of the `SELECT` clause (where
  `1` is the first element).
</Info>

For example, to find the average cab fare from the taxi data set:

```sql Aggregation without GROUP BY Example theme={null}
SELECT ROUND(AVG(total_amount),2) AS "Average_Fare"
FROM demo.nyctaxi
```

To find the minimum, maximum, & average trip distances, as well as the average
passenger count for each vendor per year from the taxi data set (weeding out
data with errant trip distances):

```sql Aggregate with GROUP BY Example theme={null}
SELECT
    vendor_id AS Vendor_ID,
    YEAR(pickup_datetime) AS Year,
    MAX(trip_distance) AS Max_Trip,
    MIN(trip_distance) AS Min_Trip,
    ROUND(AVG(trip_distance),2) AS Avg_Trip,
    INT(AVG(passenger_count)) AS Avg_Passenger_Count
FROM demo.nyctaxi
WHERE
    trip_distance > 0 AND
    trip_distance < 100
GROUP BY vendor_id, 2
ORDER BY Vendor_ID, Year
```

<a id="sql-grouping" />

## Grouping

The `GROUP BY` clause can also be used to apply the following
[grouping functions](/content/sql/query#sql-grouping-functions) over the values within each
group:

* [ROLLUP](/content/sql/query#sql-rollup)
* [CUBE](/content/sql/query#sql-cube)
* [GROUPING SETS](/content/sql/query#sql-grouping-sets)

With each of these, the `GROUPING()` aggregate function can be used to
distinguish aggregated *null* values in the data from *null* values generated by
the `ROLLUP`, `CUBE`, or `GROUPING SETS` *grouping function*.

For instance, the following `CASE` will turn the aggregated *null* values in
the `Sector` column into an `<UNKNOWN SECTOR>` group and the *null* value
generated by the *grouping function* into an `<ALL SECTORS>` group:

```sql GROUPING Expression Example theme={null}
CASE
    WHEN (GROUPING(Sector) = 1) THEN '<ALL SECTORS>'
    ELSE NVL(Sector, '<UNKNOWN SECTOR>')
END AS SectorGroup,
```

<a id="sql-grouping-rollup" />

<a id="sql-rollup" />

### ROLLUP

The [ROLLUP(expr list)](/content/concepts/rollup) function calculates *n* + 1
aggregates for *n* number of columns in `expr list`.

For example, the following query will aggregate the average opening stock price
for these groups:

* Each market sector & stock symbol pair
* Each market sector
* All sectors and symbols

```sql ROLLUP Example theme={null}
SELECT
    CASE
        WHEN (GROUPING(Sector) = 1) THEN '<ALL SECTORS>'
        ELSE NVL(Sector, '<UNKNOWN SECTOR>')
    END AS SectorGroup,
    CASE
        WHEN (GROUPING(Symbol) = 1) THEN '<ALL SYMBOLS>'
        ELSE NVL(Symbol, '<UNKNOWN SYMBOL>')
    END AS SymbolGroup,
    DECIMAL(AVG("Open"), 7, 2) AS AvgOpen
FROM demo.Stocks
GROUP BY ROLLUP(Sector, Symbol)
ORDER BY SectorGroup, SymbolGroup
```

<a id="sql-grouping-cube" />

<a id="sql-cube" />

### CUBE

The [CUBE(expr list)](/content/concepts/cube) function calculates 2<sup>n</sup>
aggregates for *n* number of columns in `expr list`.

For example, the following query will aggregate the average opening stock price
for these groups:

* Each market sector & stock symbol pair
* Each market sector
* Each stock symbol
* All sectors and symbols

```sql CUBE Example theme={null}
SELECT
    CASE
        WHEN (GROUPING(Sector) = 1) THEN '<ALL SECTORS>'
        ELSE NVL(Sector, '<UNKNOWN SECTOR>')
    END AS SectorGroup,
    CASE
        WHEN (GROUPING(Symbol) = 1) THEN '<ALL SYMBOLS>'
        ELSE NVL(Symbol, '<UNKNOWN SYMBOL>')
    END AS SymbolGroup,
    DECIMAL(AVG("Open"), 7, 2) AS AvgOpen
FROM demo.Stocks
GROUP BY CUBE(Sector, Symbol)
ORDER BY SectorGroup, SymbolGroup
```

<a id="sql-grouping-groupingsets" />

<a id="sql-grouping-sets" />

### GROUPING SETS

The [GROUPING SETS(expr list)](/content/concepts/grouping_sets) function
calculates aggregates for each group of columns in `expr list`.

For example, the following query will aggregate the average opening stock price
for these groups:

* Each market sector
* Each stock symbol
* All sectors and symbols

```sql GROUPING SETS Example theme={null}
SELECT
    CASE
        WHEN (GROUPING(Sector) = 1) THEN '<ALL SECTORS>'
        ELSE NVL(Sector, '<UNKNOWN SECTOR>')
    END AS SectorGroup,
    CASE
        WHEN (GROUPING(Symbol) = 1) THEN '<ALL SYMBOLS>'
        ELSE NVL(Symbol, '<UNKNOWN SYMBOL>')
    END AS SymbolGroup,
    DECIMAL(AVG("Open"), 7, 2) AS AvgOpen
FROM demo.Stocks
GROUP BY GROUPING SETS((Sector), (Symbol), ())
ORDER BY SectorGroup, SymbolGroup
```

<a id="sql-window" />

<a id="sql-window" />

## Window

[Window functions](/content/concepts/window) are available through the use of the
`OVER` clause, which can partition rows into frames. Different
[types of functions](/content/sql/query#sql-window-types) can be used to aggregate data
over a sliding window.

```sql title="Window Function Syntax" theme={null}
SELECT
    <window function> OVER (
        [PARTITION BY <column expression list>]
        [ORDER BY <ordering expression list>]
        [
            <RANGE | ROWS>
            <
                <UNBOUNDED PRECEDING | <number> PRECEDING | CURRENT ROW | <number> FOLLOWING>
                |
                BETWEEN <UNBOUNDED PRECEDING | <number> PRECEDING | CURRENT ROW | <number> FOLLOWING>
                    AND <UNBOUNDED FOLLOWING | <number> PRECEDING | CURRENT ROW | <number> FOLLOWING>
            >
        ]
    ) [AS <alias>]
```

The default frame type is:

```
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
```

### Parameters

<AccordionGroup>
  <Accordion title="<window function>" id="<window-function>" defaultOpen>
    One of the supported [window functions](/content/sql/query#sql-window-types) listed below
  </Accordion>

  <Accordion title="PARTITION BY" id="partition-by" defaultOpen>
    Optional list of columns and/or column expressions to use in partitioning the data.  The window
    function will be applied separately to each partition, defined by the set of records containing
    the same value(s) for the specified partition-by column(s).  If no `PARTITION BY` clause is
    given, the window function will be calculated over the entire data set.
  </Accordion>

  <Accordion title="ORDER BY" id="order-by" defaultOpen>
    Clause defining the ordering of records within each partition before applying the window
    function; optional when using `FIRST_VALUE()` or `LAST_VALUE()`.

    The ordering expression syntax is:

    ```
    <column name/alias/expression/position> [ASC | DESC] [NULLS FIRST | NULLS LAST]
    ```

    The default sort order is ascending (`ASC`).  The default null ordering is `NULLS FIRST` when
    using ascending order and `NULLS LAST` when using descending order.

    <Info>
      Only one column can be specified in the ordering expression list when
      using `RANGE`.  When using `ROWS`, the frame is applied after any
      ordering; so, while several columns may appear in the order expression list,
      there will be only one `ROWS` clause following the list.
    </Info>
  </Accordion>

  <Accordion title="RANGE" id="range" defaultOpen>
    Range-based frame used in applying the window function to each record.  The frame is based on the
    values in the column or column expression used in the `ORDER BY` clause.  All records with this
    value within the specified relation to the current record's value will be used in calculating its
    window function result.

    A range-based frame can be specified for any [aggregate function](/content/sql/query#sql-window-types-agg)
    or the `FIRST_VALUE()` or `LAST_VALUE()` [ranking function](/content/sql/query#sql-window-types-rank).

    For a frame between a specified lower bound and the current row:

    ```
    RANGE <lower frame bound>
    ```

    For a frame between a specified lower and upper bound:

    ```
    RANGE BETWEEN <lower frame bound> AND <upper frame bound>
    ```

    The *frame bound* can be one of the following:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Frame Bound</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>UNBOUNDED PRECEDING</code></td>
            <td>All records in the partition before the one at the upper bound; cannot be used as an upper bound</td>
          </tr>

          <tr>
            <td><code>\<number> PRECEDING</code></td>
            <td>All records in the partition with an <code>ORDER BY</code> value between the current record's value and <code>\<number></code> less than the current record's value, inclusive</td>
          </tr>

          <tr>
            <td><code>CURRENT ROW</code></td>
            <td>The current record being processed by the window function, as well as all *peer rows* (rows with the same ordering value)</td>
          </tr>

          <tr>
            <td><code>\<number> FOLLOWING</code></td>
            <td>All records in the partition with an <code>ORDER BY</code> value between the current record's value and <code>\<number></code> more than the current record's value, inclusive</td>
          </tr>

          <tr>
            <td><code>UNBOUNDED FOLLOWING</code></td>
            <td>All records in the partition after the one at the lower bound; cannot be used as a lower bound</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="ROWS" id="rows" defaultOpen>
    Row-based frame used in applying the window function to each record.  The frame is based on the
    position of records, as determined by the `ORDER BY` clause.  All records within the specified
    ordered distance from a given record will be used in calculating its window function value.

    A row-based frame can be specified for any [aggregate function](/content/sql/query#sql-window-types-agg)
    or the `FIRST_VALUE()` or `LAST_VALUE()` [ranking function](/content/sql/query#sql-window-types-rank).

    For a frame between a specified lower bound and the current row:

    ```
    ROWS <lower frame bound>
    ```

    For a frame between a specified lower and upper bound:

    ```
    ROWS BETWEEN <lower frame bound> AND <upper frame bound>
    ```

    The *frame bound* can be one of the following:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Frame Bound</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>UNBOUNDED PRECEDING</code></td>
            <td>All records in the partition before the one at the upper bound; cannot be used as an upper bound</td>
          </tr>

          <tr>
            <td><code>\<number> PRECEDING</code></td>
            <td>All records in the partition from the one <code>\<number></code> records before the current record through the record at the upper bound</td>
          </tr>

          <tr>
            <td><code>CURRENT ROW</code></td>
            <td>The current record being processed by the window function</td>
          </tr>

          <tr>
            <td><code>\<number> FOLLOWING</code></td>
            <td>All records in the partition from the record at the lower bound through the one <code>\<number></code> records after the current record</td>
          </tr>

          <tr>
            <td><code>UNBOUNDED FOLLOWING</code></td>
            <td>All records in the partition after the one at the lower bound; cannot be used as a lower bound</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="<alias>" id="<alias>" defaultOpen>
    Column alias to apply to the window function result column
  </Accordion>
</AccordionGroup>

<a id="sql-window-types" />

<a id="sql-window-types-agg" />

### Aggregate Functions

<AccordionGroup>
  <Accordion title="AVG(expr)" id="avg-expr" defaultOpen>
    Calculates the average of the given expression `expr` over the specified window frame
  </Accordion>

  <Accordion title="COUNT(expr)" id="count-expr" defaultOpen>
    Calculates the count of the given expression `expr` over the specified window frame
  </Accordion>

  <Accordion title="MAX(expr)" id="max-expr" defaultOpen>
    Calculates the maximum value of the given expression `expr` over the specified window frame
  </Accordion>

  <Accordion title="MEAN(expr)" id="mean-expr" defaultOpen>
    Alias for `AVG()`. Calculates the average of the given expression `expr` over the specified
    window frame
  </Accordion>

  <Accordion title="MIN(expr)" id="min-expr" defaultOpen>
    Calculates the minimum value of the given expression `expr` over the specified window frame
  </Accordion>

  <Accordion title="PRODUCT(expr)" id="product-expr" defaultOpen>
    Calculates the product of the given expression `expr` over the specified window frame
  </Accordion>

  <Accordion title="RATIO_TO_REPORT(expr)" id="ratio_to_report-expr" defaultOpen>
    Calculates the ratio of the value of `expr` to the sum of `expr` over the specified window
    frame.  Note that `ORDER BY` is not supported for this function.
  </Accordion>

  <Accordion title="STDDEV(expr)" id="stddev-expr" defaultOpen>
    Alias for `STDDEV_POP()`. Calculates the population standard deviation of the given
    expression `expr` over the specified window frame
  </Accordion>

  <Accordion title="STDDEV_POP(expr)" id="stddev_pop-expr" defaultOpen>
    Calculates the population standard deviation of the given expression `expr` over the specified
    window frame
  </Accordion>

  <Accordion title="STDDEV_SAMP(expr)" id="stddev_samp-expr" defaultOpen>
    Calculates the sample standard deviation of the given expression `expr` over the specified
    window frame
  </Accordion>

  <Accordion title="SUM(expr)" id="sum-expr" defaultOpen>
    Calculates the sum of the given expression `expr` over the specified window frame
  </Accordion>

  <Accordion title="VAR(expr)" id="var-expr" defaultOpen>
    Alias for `VAR_POP()`. Calculates the population variance of the given expression `expr` over
    the specified window frame
  </Accordion>

  <Accordion title="VAR_POP(expr)" id="var_pop-expr" defaultOpen>
    Calculates the population variance of the given expression `expr` over the specified window
    frame
  </Accordion>

  <Accordion title="VAR_SAMP(expr)" id="var_samp-expr" defaultOpen>
    Calculates the sample variance of the given expression `expr` over the specified window frame
  </Accordion>
</AccordionGroup>

<a id="sql-window-types-rank" />

### Ranking Functions

<AccordionGroup>
  <Accordion title="CUME_DIST()" id="cume_dist" defaultOpen>
    The relative position of the current row within the cumulative distribution of the selected
    partition, expressed as a percentage from `0` (exclusive) to `1` (inclusive). The formula for
    this calculation is as follows:

    ```
    (count of <= records within partition) / (partition row count)
    ```

    This function is shorthand for using the `COUNT()` function in separate partition statements to
    arrive at the same result:

    ```sql theme={null}
    DOUBLE
    (
        COUNT(*) OVER
        (
            PARTITION BY <partition_column>
            ORDER BY <sort_column>
        )
    ) /
    (
        COUNT(*) OVER
        (
            PARTITION BY <partition_column>
            ORDER BY <sort_column>
            ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
        )
    )
    ```
  </Accordion>

  <Accordion title="DENSE_RANK()" id="dense_rank" defaultOpen>
    Number of the current row within the selected partition except rows with identical values
    evaluate to different ranks. Starts at 1
  </Accordion>

  <Accordion title="FIRST_VALUE(<column>) [<IGNORE | RESPECT> NULLS]" id="first_value-<column>-<ignore-|-respect>-nulls" defaultOpen>
    The value found in the first row within a frame of the given expression. Optionally, add
    `IGNORE NULLS` or `RESPECT NULLS` to the function syntax to ignore or respect `nulls`,
    respectively.
  </Accordion>

  <Accordion title="LAG(<column>[, <num>]) [<IGNORE | RESPECT> NULLS]" id="lag-<column>-<num>-<ignore-|-respect>-nulls" defaultOpen>
    The value of the row before the given expression's value. Provide an additional comma-separated
    value to specify which row to select, e.g., `LAG(vendor_id, 3)` would list the value in the
    `vendor_id` column from three rows prior to the current row. Optionally, add `IGNORE NULLS`
    or `RESPECT NULLS` to the function syntax to ignore or respect `nulls` respectively.
  </Accordion>

  <Accordion title="LAST_VALUE(<column>) [<IGNORE | RESPECT> NULLS]" id="last_value-<column>-<ignore-|-respect>-nulls" defaultOpen>
    The value found in the last row within a frame of the given expression. Optionally, add
    `IGNORE NULLS` or `RESPECT NULLS` to the function syntax to ignore or respect
    `nulls` respectively.
  </Accordion>

  <Accordion title="LEAD(<column>[, <num>]) [<IGNORE | RESPECT> NULLS]" id="lead-<column>-<num>-<ignore-|-respect>-nulls" defaultOpen>
    The value of the row after the given expression's value. Provide an additional comma-separated
    value to specify which row to select, e.g., `LEAD(vendor_id, 3)` would list the value in the
    `vendor_id` column from three rows after the current row. Optionally, add `IGNORE NULLS`
    or `RESPECT NULLS` to the function syntax to ignore or respect `nulls` respectively.
  </Accordion>

  <Accordion title="NTILE(<num of groups>)" id="ntile-<num-of-groups>" defaultOpen>
    The group number of the row after partitioning the rows into `num of groups` groups.  For
    example, `NTILE(4)` will partition data by quartiles and return the associated group number,
    `1` to `4`.
  </Accordion>

  <Accordion title="PERCENT_RANK()" id="percent_rank" defaultOpen>
    The rank of the current row within the selected partition, expressed as a percentage from `0`
    to `1`, inclusive. The formula for this calculation is as follows:

    ```
    (rank within partition - 1) / (partition row count - 1)
    ```

    This function is shorthand for using the `RANK()` & `COUNT()` functions in separate partition
    statements to arrive at the same result:

    ```sql theme={null}
    DOUBLE
    (
        RANK() OVER
        (
            PARTITION BY <partition_column>
            ORDER BY <sort_column>
        ) - 1
    ) /
    (
        COUNT(*) OVER
        (
            PARTITION BY <partition_column>
            ORDER BY <sort_column>
            ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
        ) - 1
    )
    ```
  </Accordion>

  <Accordion title="RANK()" id="rank" defaultOpen>
    Number of the current row within the selected partition. However, rows with identical values
    evaluate to the same rank. Starts at 1
  </Accordion>

  <Accordion title="ROW_NUMBER()" id="row_number" defaultOpen>
    Number of the current row within the selected partition. Starts at 1
  </Accordion>
</AccordionGroup>

### Examples

To calculate the rolling sum of total amounts collected by each
taxi vendor over the course of a given day, as well as the number of other trips
that occurred within 5 minutes of each trip:

```sql Window Rolling Sum Example theme={null}
SELECT
    vendor_id,
    pickup_datetime,
    total_amount,
    passenger_count,
    DECIMAL
    (
        SUM(total_amount) OVER
            (
                PARTITION BY vendor_id
                ORDER BY pickup_datetime
                ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
            )
    ) AS growing_sum,
    COUNT(*) OVER
        (
            PARTITION BY vendor_id
            ORDER BY LONG(pickup_datetime)
            RANGE BETWEEN 300000 PRECEDING AND 300000 FOLLOWING
        ) AS trip_demand
FROM demo.nyctaxi
WHERE pickup_datetime >= '2015-01-01' AND pickup_datetime < '2015-01-01 02:00:00'
ORDER BY
    vendor_id,
    pickup_datetime
```

To calculate a 5-before and 10-after moving average of 4-passenger trip
distances per vendor over the course of a given day:

```sql Window Moving Average Example theme={null}
SELECT
    vendor_id,
    pickup_datetime,
    trip_distance,
    AVG(trip_distance) OVER
        (
            PARTITION BY vendor_id
            ORDER BY pickup_datetime
            ROWS BETWEEN 5 PRECEDING AND 10 FOLLOWING
        ) AS local_avg_dist
FROM demo.nyctaxi
WHERE
    passenger_count = 4 AND
    pickup_datetime >= '2015-01-01' AND pickup_datetime < '2015-01-02'
ORDER BY
    vendor_id,
    pickup_datetime
```

To rank, by vendor, the total amounts collected from 3-passenger trips on a
given day:

```sql Window Ranking Example theme={null}
SELECT
    vendor_id,
    pickup_datetime,
    dropoff_datetime,
    total_amount AS fare,
    RANK() OVER (PARTITION BY vendor_id ORDER BY total_amount) AS ranked_fare,
    DECIMAL(PERCENT_RANK() OVER (PARTITION BY vendor_id ORDER BY total_amount)) * 100 AS percent_ranked_fare
FROM demo.nyctaxi
WHERE
    passenger_count = 3 AND
    pickup_datetime >= '2015-01-11' AND pickup_datetime < '2015-01-12'
ORDER BY
    vendor_id,
    pickup_datetime
```

To compare each trip's total amount to the lowest (ignoring nulls), highest
(ignoring nulls), & average total amount for 5-passenger trips for each vendor
over the course of a given day:

```sql Window FIRST_VALUE Example theme={null}
SELECT
    vendor_id,
    pickup_datetime,
    tip_amount,
    tip_amount -
        FIRST_VALUE(tip_amount) IGNORE NULLS OVER
            (PARTITION BY vendor_id ORDER BY tip_amount) AS vs_lowest_tip,
    tip_amount -
        DECIMAL
        (
            AVG(tip_amount) OVER
                (
                    PARTITION BY vendor_id
                    ORDER BY tip_amount
                    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
                )
        ) AS vs_average_tip,
    tip_amount -
        FIRST_VALUE(tip_amount) IGNORE NULLS OVER
            (PARTITION BY vendor_id ORDER BY tip_amount DESC) AS vs_highest_tip
FROM demo.nyctaxi
WHERE
    passenger_count = 5 AND trip_distance > 0 AND tip_amount > 0 AND
    pickup_datetime >= '2015-04-17' AND pickup_datetime < '2015-04-18'
ORDER BY
    vendor_id,
    pickup_datetime
```

To compare each vendor's average total amount to their average total amount
within the interquartile range:

```sql Window N-Tile Example theme={null}
SELECT
    vendor_id,
    DECIMAL(AVG(total_amount)) AS average_total_amount,
    DECIMAL(AVG(IF(quartile IN (2,3), total_amount, null))) AS average_interq_range_total_amount
FROM
(
    SELECT
        vendor_id,
        total_amount,
        NTILE(4) OVER (PARTITION BY vendor_id ORDER BY total_amount) quartile
    FROM
        demo.nyctaxi
)
GROUP BY vendor_id
ORDER BY vendor_id
```

<a id="sql-pivot" />

<a id="sql-pivot" />

## PIVOT

The `PIVOT` clause can be used to [pivot](/content/concepts/pivot)
columns, "rotating" column values into multiple columns (one for each value),
creating wider and shorter denormalized tables from longer, more normalized
tables.

```sql title="PIVOT Syntax" theme={null}
<select statement>
PIVOT
(
    <aggregate expression [AS <alias>]>[,...]
    FOR <column> IN (<column list>)
)
```

For example, given a source table `phone_number`, which lists each phone number
for a customer as a separate record in the table, a *pivot* operation can be
performed, creating a single record per customer with the home, work, & cell
phone numbers as separate columns.

With this data:

```PIVOT Input theme={null}
+--------+--------------+----------------+
| name   | phone_type   | phone_number   |
+--------+--------------+----------------+
| Jane   | Home         | 123-456-7890   |
| Jane   | Work         | 111-222-3333   |
| John   | Home         | 123-456-7890   |
| John   | Cell         | 333-222-1111   |
+--------+--------------+----------------+
```

The following *pivot* operation can be applied:

```sql PIVOT Example theme={null}
SELECT
    name,
    Home_Phone,
    Work_Phone,
    Cell_Phone
FROM
    example.phone_list
PIVOT
(
    MAX(phone_number) AS Phone
    FOR phone_type IN ('Home', 'Work', 'Cell')
)
```

The data will be pivoted into a table like this:

```PIVOT Output theme={null}
+--------+----------------+----------------+----------------+
| name   | Home_Phone     | Work_Phone     | Cell_Phone     |
+--------+----------------+----------------+----------------+
| Jane   | 123-456-7890   | 111-222-3333   |                |
| John   | 123-456-7890   |                | 333-222-1111   |
+--------+----------------+----------------+----------------+
```

<a id="sql-unpivot" />

<a id="sql-unpivot" />

## UNPIVOT

The `UNPIVOT` clause can be used to [unpivot](/content/concepts/unpivot)
columns, "rotating" row values into column values, creating longer, more
normalized tables from shorter, more denormalized tables.

```sql title="UNPIVOT Syntax" theme={null}
<select statement>
UNPIVOT
(
    <value_column> FOR <var_column> IN (<column list>)
)
```

For example, given a source table `customer_contact`, which lists the home,
work, & cell phone numbers for each customer in the table, an *unpivot*
operation can be performed, creating separate home, work, & cell phone records
for each customer.

With this data:

```UNPIVOT Input theme={null}
+--------+----------------+----------------+----------------+
| name   | home_phone     | work_phone     | cell_phone     |
+--------+----------------+----------------+----------------+
| Jane   | 123-456-7890   | 111-222-3333   |                |
| John   | 123-456-7890   |                | 333-222-1111   |
+--------+----------------+----------------+----------------+
```

The following *unpivot* operation can be applied:

```sql UNPIVOT Example theme={null}
SELECT *
FROM
(
    SELECT
        name,
        Home_Phone AS Home,
        Work_Phone AS Work,
        Cell_Phone AS Cell
    FROM
        example.customer_contact
)
UNPIVOT (
    phone_number FOR phone_type IN (Home, Work, Cell)
)
```

The data will be unpivoted into a table like this:

```UNPIVOT Output theme={null}
+--------+----------------+--------------+
| name   | phone_number   | phone_type   |
+--------+----------------+--------------+
| Jane   | 123-456-7890   | Home         |
| John   | 123-456-7890   | Home         |
| Jane   | 111-222-3333   | Work         |
| John   | 333-222-1111   | Cell         |
+--------+----------------+--------------+
```

<Info>
  If the original column names can be used as the values of the unpivot
  key, as is, the pre-selection and renaming of those columns using a subquery
  in the `FROM` clause can be eliminated.

  For example, unpivoting without aliasing the quarterly grade columns will
  result in those exact column names being used as the quarter values:
</Info>

```sql UNPIVOT without Aliases Example theme={null}
SELECT *
FROM example.student_grade
UNPIVOT
(
    grade FOR quarter IN (q1_grade, q2_grade, q3_grade, q4_grade)
)
```

```UNPIVOT without Aliases Output theme={null}
+--------------+-------------+------------+
|   student_id |       grade | quarter    |
+--------------+-------------+------------+
|            1 |   80.0      | q1_grade   |
|            2 |   82.0      | q1_grade   |
|            3 |   73.0      | q1_grade   |
|            1 |   90.0      | q2_grade   |
|            3 |   77.0      | q2_grade   |
|            1 |   85.0      | q3_grade   |
|            2 |   87.0      | q3_grade   |
|            3 |   97.0      | q3_grade   |
|            1 |   95.0      | q4_grade   |
|            2 |   92.0      | q4_grade   |
+--------------+-------------+------------+
```

<a id="sql-set-ops" />

## Set Operations

There are three types of supported set operations, each having the option of
returning duplicate records in the result set by using the keyword `ALL`:

* [UNION \[ALL\]](/content/sql/query#sql-union) - return all records from both source data sets
* [INTERSECT \[ALL\]](/content/sql/query#sql-intersect) - return only records that exist in
  both source data sets
* [EXCEPT \[ALL\]](/content/sql/query#sql-except) - return all records that exist in the first
  data set, but not in the second

<a id="sql-union" />

### UNION

The `UNION` set operator creates a single list of records from the results of
two `SELECT` statements.  Use the `ALL` keyword to keep all records from
both sets; omit it to remove duplicate records and form a single list of records
unique between the two sets.  See [Limitations and Cautions](/content/concepts/unions#union-limitations) for limitations.

```sql title="UNION Syntax" theme={null}
<select statement>
UNION [ALL]
<select statement>
```

For example, given a table of lunch menu items and another table of dinner menu
items, a `UNION` can be used to return all unique lunch & dinner menu items
together, including items that are the same on both menus, but of a different
price:

```sql UNION Example theme={null}
SELECT
    food_name,
    category,
    price
FROM
    example.lunch_menu
UNION
SELECT
    food_name,
    category,
    price
FROM
    example.dinner_menu
```

<Info>
  Since the example includes `price` and all columns selected must
  match between the two sets for an item to be considered a duplicate,
  a lunch item that is priced differently as a dinner item would also
  appear in the result set.
</Info>

A `UNION ALL` can be used to return all lunch & dinner menu items together,
including duplicates:

```sql UNION ALL Example theme={null}
SELECT
    food_name,
    category,
    price
FROM
    example.lunch_menu
UNION ALL
SELECT
    food_name,
    category,
    price
FROM
    example.dinner_menu
```

<a id="sql-intersect" />

### INTERSECT

The `INTERSECT` set operator creates a single list of records that exist in
both of the result sets from two `SELECT` statements.  Use the `ALL` keyword
to keep duplicate records that exist in both sets; omit it to remove duplicate
records and form a single list of records that exist in both sets.  See
[Limitations](/content/concepts/intersect#intersect-limitations) for limitations.

```sql title="INTERSECT Syntax" theme={null}
<select statement>
INTERSECT [ALL]
<select statement>
```

For example, given a table of lunch menu items and another table of dinner menu
items, an `INTERSECT` can be used to return all lunch menu items (excluding
duplicates) that are also dinner items for the same price:

```sql INTERSECT Example theme={null}
SELECT
    food_name,
    category,
    price
FROM
    example.lunch_menu
INTERSECT
SELECT
    food_name,
    category,
    price
FROM
    example.dinner_menu
```

<Info>
  Since the example includes `price` and all columns selected must
  match between the two sets for an item to be included, a lunch item
  that is priced differently as a dinner item would not appear in the
  result set.
</Info>

<a id="sql-except" />

### EXCEPT

The `EXCEPT` set operator performs set subtraction, creating a single list of
records that exist in the first `SELECT` statement's result set, but not in
the second `SELECT` statement's result set.  Use the `ALL` keyword to keep
duplicate records that exist in the first set but not in the second; omit it to
remove duplicate records and form a single list of records that exist in the
first set but not the second.  See [Limitations](/content/concepts/except#except-limitations) for limitations:

```sql title="EXPECT Syntax" theme={null}
<select statement>
EXCEPT [ALL]
<select statement>
```

For example, given a table of lunch menu items and another table of dinner menu
items, an `EXCEPT` can be used to return all lunch menu items (excluding
duplicates) that are not also dinner items for the same price:

```sql EXPECT Example theme={null}
SELECT
    food_name,
    category,
    price
FROM
    example.lunch_menu
EXCEPT
SELECT
    food_name,
    category,
    price
FROM
    example.dinner_menu
```

<Info>
  Since the example includes `price` and all columns selected must
  match between the two sets for an item to be eliminated, a lunch item
  that is priced differently as a dinner item would still appear in the
  result set.
</Info>

<a id="sql-with" />

<a id="sql-cte" />

## WITH (Common Table Expressions)

The `WITH` operation, also known as a *Common Table Expression (CTE)*
creates a set of data that can be assigned table & column aliases and used one
or more times in subsequent operations.  The aliased set can be used within the
`SELECT`, `FROM`, or `WHERE` clauses of a subsequent query or a subsequent
*CTE* within the same `WITH` operation.

```sql title="WITH Syntax" theme={null}
WITH [RECURSIVE]
	<cte definition>[,...]
<select statement>
```

### Parameters

<AccordionGroup>
  <Accordion title="RECURSIVE" id="recursive" defaultOpen>
    Allow one or more of the `<cte definition>` queries to be self-referential, providing for the
    possibility of [recursive queries](/content/sql/query#sql-recursive-query).
  </Accordion>

  <Accordion title="<cte definition>" id="<cte-definition>" defaultOpen>
    The subquery or one of the subqueries defined within this `WITH` clause, structured as follows:

    ```
    <cte name> [(<column alias list>)] AS (<subquery>)
    ```

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Parameter</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>\<cte name></code></td>
            <td>Table alias given to the data set returned by the *CTE*.</td>
          </tr>

          <tr>
            <td><code>\<column alias list></code></td>
            <td>List of aliases assigned to the columns the *CTE* returns.</td>
          </tr>

          <tr>
            <td><code>\<subquery></code></td>
            <td><code>SELECT</code> statement to associate with the corresponding <code>\<cte name></code>.</td>
          </tr>
        </tbody>
      </table>
    </div>

    Each column alias in `<column alias list>` is matched to each column returned by the
    corresponding `<subquery>` in the order that each were defined; e.g., for column aliases
    `(A, B, C)` used with a subquery `SELECT x, y, z ...`, alias `A` will reference column
    `x`, `B` will reference `y`, and `C` will reference `z`.  If no aliases are used, the
    names of the source columns themselves can be used to reference the data set returned by the
    subquery.
  </Accordion>

  <Accordion title="<select statement>" id="<select-statement>" defaultOpen>
    The `SELECT` statement to run with the defined `WITH` subqueries.
  </Accordion>
</AccordionGroup>

The column aliases must be unique within the `WITH` statement--no
other column or column alias can be similarly named, for example.  Also, when
used in a `FROM` clause and given a table alias, the table alias must be
preceded with `AS`.

A *CTE* can be made available to a DML or DDL statement by having the `WITH`
statement follow the `CREATE TABLE ... AS`, `INSERT`, `UPDATE`, or
`DELETE` statement (not precede it).

### Examples

To define a simple *CTE* subquery using a `WITH` clause:

```sql WITH Example theme={null}
WITH
    dept2_emp_sal_by_mgr (manager_id, sal) AS
    (
        SELECT manager_id, salary
        FROM example.employee
        WHERE dept_id = 2
    )
SELECT
    manager_id dept2_mgr_id,
    MAX(sal) dept2_highest_emp_sal_per_mgr,
    COUNT(*) as dept2_total_emp_per_mgr
FROM dept2_emp_sal_by_mgr
GROUP BY manager_id
```

To apply the *CTE* to an `INSERT` statement while using multiple *CTE*
definitions, follow the `INSERT` clause with the `WITH` clause:

```sql WITH Defining Multiple Subqueries in INSERT Example theme={null}
INSERT INTO example.dept2_emp_mgr_roster (emp_first_name, emp_last_name, mgr_first_name, mgr_last_name)
WITH
    dept2_emp AS
    (
        SELECT first_name, last_name, manager_id
        FROM example.employee
        WHERE dept_id = 2
    ),
    dept2_mgr AS
    (
        SELECT first_name, last_name, id
        FROM example.employee
        WHERE dept_id = 2
    )
SELECT d2emp.first_name, d2emp.last_name, d2mgr.first_name, d2mgr.last_name
FROM
    dept2_emp as d2emp
    JOIN dept2_mgr as d2mgr ON d2emp.manager_id = d2mgr.id
```

<a id="sql-recursive-query" />

### Recursive Queries

[Common table expressions](/content/sql/query#sql-with) are used to create
*recursive queries*, via the `RECURSIVE` option, using the following form:

```sql title="Recursive WITH Syntax" theme={null}
WITH RECURSIVE
	<cte name> AS
	(
    	<non-recursive query>
    	UNION [ALL]
    	<recursive query>
    )
<select statement>
```

Use `UNION` to remove duplicate records from the result set; use `UNION ALL`
to return all records from the recursion.

<Note>
  There is no check on queries that recurse infinitely.  Ensure
  that recursive queries are constructed with an appropriate limit.
</Note>

For instance, to query all of a given manager's subordinates:

```sql Recursive Query Example theme={null}
WITH RECURSIVE subordinates AS
(
    SELECT
        id,
        manager_id,
        first_name,
        last_name
    FROM
        example.employee
    WHERE
        id = 6
    UNION ALL
    SELECT
        e.id,
        e.manager_id,
        e.first_name,
        e.last_name
    FROM
        example.employee e
        INNER JOIN subordinates s ON s.id = e.manager_id
)
SELECT *
FROM subordinates
ORDER BY manager_id, id
```

To show the management chain for each employee in a company:

```sql Recursive Query with Recursion Trail Example theme={null}
WITH RECURSIVE subordinates AS
(
    SELECT
        id,
        manager_id,
        first_name,
        last_name,
        JSON_ARRAY(first_name || ',' || last_name) AS hierarchy
    FROM
        example.employee
    WHERE
        id = 1
    UNION ALL
    SELECT
        e.id,
        e.manager_id,
        e.first_name,
        e.last_name,
        JSON_ARRAY_APPEND(s.hierarchy, e.first_name || ',' || e.last_name) AS hierarchy
    FROM
        example.employee e
        INNER JOIN subordinates s ON s.id = e.manager_id
)
SELECT *
FROM subordinates
ORDER BY manager_id, id
```

<a id="sql-iteration" />

## Iteration

*Kinetica* supports [iteration](/content/concepts/iteration) over each
record within a data set for the purpose of creating a result set with `0` to
`N` result records per record in the original set.

This iteration can be variable, based on some value within each record, or
fixed, based on a given constant value.

The *iteration* is performed by joining against the virtual `ITER` table, as
follows:

```sql title="Iteration Syntax" theme={null}
SELECT *
FROM table, ITER
WHERE ITER.i < <column expression>
```

The `<column expression>` can be replaced by a constant for fixed *iteration*.

For example, to extract all of the individual letters from a column of words,
with one record per letter extracted (using variable iteration):

```sql Iteration Over Column Values Example theme={null}
SELECT id, word, i, SUBSTR(word, i + 1, 1) AS letter
FROM example.dictionary
JOIN ITER ON i < LENGTH(word)
ORDER BY id, i
```

To duplicate the set of words five times (using fixed iteration):

```sql Iteration Over Table Example theme={null}
SELECT i, id, word
FROM example.dictionary, ITER
WHERE i < 5
ORDER BY id, i
```

For more detail, examples, and limitations, see
[Iteration](/content/concepts/iteration).

<a id="sql-constants" />

## Constants

Each data type has an associated literal constant syntax, which can be used, for
instance, to insert constant data values into those columns.

### Numeric Constants

Integer and floating point data types can be either single-quoted or not.

```sql Numeric Constants Example theme={null}
INSERT INTO example.numeric_types (int_type1, int_type2, float_type1, float_type2)
VALUES
(
    1,
    '2',
    3.4,
    '5.6'
)
```

### String-Based Constants

String-based data types should be single-quoted.

```sql String-Based Constants Example theme={null}
INSERT INTO example.string_types (varchar_type, charn_type, ipv4_type, wkt_type)
VALUES
(
    'varchar value',
    'charN value',
    '12.34.56.78',
    'POINT(0 0)'
)
```

### Binary Constants

Binary types can be represented in either of the following forms:

* single-quoted or unquoted base-10
* single-quoted hexadecimal

```sql Binary Constants Example theme={null}
INSERT INTO example.byte_types (bytes_type)
VALUES
    (12345678901234567890),
    ('12345678901234567890'),
    ('0x00AB54A98CEB1F0AD2')
```

### Date/Time Constants

Kinetica accepts unqualified single-quoted date/time values, ANSI SQL, and ODBC
escape sequences in the following formats:

| Data Type | Native                              | ANSI                                  | ODBC                             |
| --------- | ----------------------------------- | ------------------------------------- | -------------------------------- |
| Date      | `'YYYY-MM-DD'`                      | `DATE 'YYYY-MM-DD'`                   | `{d 'YYYY-MM-DD'}`               |
| Time      | `'HH:MI:SS.mmm'`                    | `TIME 'HH:MI:SS.mmm'`                 | `{t 'HH:MI:SS.mmm'}`             |
| DateTime  | `'YYYY-MM-DD[T\| ]HH:MI:SS.mmm[Z]'` | `TIMESTAMP 'YYYY-MM-DD HH:MI:SS.mmm'` | `{ts 'YYYY-MM-DD HH:MI:SS.mmm'}` |
| Timestamp | `'YYYY-MM-DD[T\| ]HH:MI:SS.mmm[Z]'` | `TIMESTAMP 'YYYY-MM-DD HH:MI:SS.mmm'` | `{ts 'YYYY-MM-DD HH:MI:SS.mmm'}` |

```sql Native Date/Time Constants Example theme={null}
INSERT INTO example.date_time_types (date_type, time_type, datetime_type, timestamp_type)
VALUES
(
    '2000-01-02',
    '12:34:56.789',
    '2000-01-02 12:34:56.789',
    '2000-01-02 12:34:56.789'
),
(
    '2000-1-02',
    '1:23:45.678',
    '2000-01-02T12:34:56.789Z',
    '2000-1-02 1:23:45.678'
)
```

```sql ANSI Date/Time Constants Example theme={null}
INSERT INTO example.date_time_types (date_type, time_type, datetime_type, timestamp_type)
VALUES
(
    DATE '2000-01-02',
    TIME '12:34:56.789',
    TIMESTAMP '2000-01-02 12:34:56.789',
    TIMESTAMP '2000-01-02 12:34:56.789'
)
```

```sql ODBC Date/Time Constants Example theme={null}
INSERT INTO example.date_time_types (date_type, time_type, datetime_type, timestamp_type)
VALUES
(
    {d '2000-01-02'},
    {t '12:34:56.789'},
    {ts '2000-01-02 12:34:56.789'},
    {ts '2000-01-02 12:34:56.789'}
)
```

<a id="sql-expressions" />

## Expressions

An *expression* can consist of a literal constant, a column name, or a function
applied to a constant or column name.  A *compound expression* is an operation
or function applied to one or more *expressions*.

The following are the supported *expression operators*:

* `+` *addition*
* `-` *subtraction*
* `*` *multiplication*
* `/` *division*
* `()` *grouping*
* `||` *string concatenation*

<a id="sql-functions" />

<a id="sql-array-functions" />

## Array Functions

<a id="sql-array-functions-scalar" />

### Scalar Functions

<AccordionGroup>
  <Accordion title="ARRAY_APPEND(array, value)" id="array_append-array-value" defaultOpen>
    Returns an array consisting of `array` with `value` appended to the end.
  </Accordion>

  <Accordion title="ARRAY_CONCAT(arr1, arr2)" id="array_concat-arr1-arr2" defaultOpen>
    Returns an array consisting of all the elements of array `arr1` followed by all of
    the elements of array `arr2`.
  </Accordion>

  <Accordion title="ARRAY_CONTAINS(array, value)" id="array_contains-array-value" defaultOpen>
    Returns true if `value` is present in `array`.
  </Accordion>

  <Accordion title="ARRAY_CONTAINS_ALL(arr1, arr2)" id="array_contains_all-arr1-arr2" defaultOpen>
    Returns true if every value in array `arr2` is present in array `arr1`; otherwise
    returns false.
  </Accordion>

  <Accordion title="ARRAY_CONTAINS_ANY(arr1, arr2)" id="array_contains_any-arr1-arr2" defaultOpen>
    Returns true if any value in array `arr2` is present in array `arr`; otherwise
    returns false.
  </Accordion>

  <Accordion title="ARRAY_DISTINCT(array)" id="array_distinct-array" defaultOpen>
    Returns an array consisting of `array` values with duplicates removed.
  </Accordion>

  <Accordion title="ARRAY_EMPTY(array)" id="array_empty-array" defaultOpen>
    Returns true if `array` is empty; otherwise returns false.
  </Accordion>

  <Accordion title="ARRAY_EXCEPT(arr1, arr2)" id="array_except-arr1-arr2" defaultOpen>
    Returns an array consisting of all of the elements of array `arr1` with the ones that
    also appear in array `arr2` removed.
  </Accordion>

  <Accordion title="ARRAY_INTERSECT(arr1, arr2)" id="array_intersect-arr1-arr2" defaultOpen>
    Returns an array consisting of all of the elements of array `arr1` that also appear
    in array `arr2`.
  </Accordion>

  <Accordion title="ARRAY_ITEM(array, pos)" id="array_item-array-pos" defaultOpen>
    Returns the item in `array` at the given 1-based `pos` position.

    See [examples](/content/concepts/array#array-func-ex-item).
  </Accordion>

  <Accordion title="ARRAY_LENGTH(array)" id="array_length-array" defaultOpen>
    Returns the number of items in the given `array` at the 1st dimension.

    See [examples](/content/concepts/array#array-func-ex-len).
  </Accordion>

  <Accordion title="ARRAY_LOWER(array, dim)" id="array_lower-array-dim" defaultOpen>
    Returns the lowest index of `array` in the given `dim` dimension; since all arrays
    are 1-dimensional, only specifying a dimension of `1` will return a value, and since
    array indices are 1-based, that value will always be `1`.
  </Accordion>

  <Accordion title="ARRAY_NDIMS(array)" id="array_ndims-array" defaultOpen>
    Returns the number of dimensions in the given `array`; since all arrays are
    1-dimensional, that number will always be `1`.
  </Accordion>

  <Accordion title="ARRAY_NOT_EMPTY(array)" id="array_not_empty-array" defaultOpen>
    Returns true if `array` is not empty; otherwise returns false.
  </Accordion>

  <Accordion title="ARRAY_SLICE(array, from, to)" id="array_slice-array-from-to" defaultOpen>
    Returns an array consisting of the values from `array` between the `from` index
    (inclusive) up to the `to` index (exclusive) using 0-based indexing. Negative indexes
    are treated as offsets from the end of the array.
  </Accordion>

  <Accordion title="ARRAY_TO_STRING(array, delim)" id="array_to_string-array-delim" defaultOpen>
    Converts the items of `array` into a string delimited by `delim`.

    See [examples](/content/concepts/array#array-func-ex-atos).
  </Accordion>

  <Accordion title="ARRAY_UPPER(array, dim)" id="array_upper-array-dim" defaultOpen>
    Returns the highest index of `array` in the given `dim` dimension; since all arrays
    are 1-dimensional, only specifying a dimension of `1` will return a value, and since
    array indices are 1-based, that value will always be equivalent to `ARRAY_LENGTH`.
  </Accordion>

  <Accordion title="MAKE_ARRAY(value)" id="make_array-value" defaultOpen>
    Returns an array consisting of the single `value` element.
  </Accordion>

  <Accordion title="STRING_TO_ARRAY(str, delim)" id="string_to_array-str-delim" defaultOpen>
    Converts the values in `str`, delimited by `delim`, into an array.

    See [examples](/content/concepts/array#array-func-ex-stoa).
  </Accordion>
</AccordionGroup>

<a id="sql-array-functions-agg" />

### Aggregation/Transposition Functions

The following functions can be used on [array](/content/concepts/array)
columns within [aggregations](/content/sql/query#sql-aggregation).

These functions can be used to convert primitive column values into arrays of
those values (aggregation) or to convert array columns into columns of primitive
values (unnest).

<AccordionGroup>
  <Accordion title="ARRAY_AGG(expr)" id="array_agg-expr" defaultOpen>
    Combines column values within a group into a single *array* of those values.

    See [examples](/content/concepts/array#array-func-agg-ex-agg).
  </Accordion>

  <Accordion title="ARRAY_AGG_DISTINCT(expr)" id="array_agg_distinct-expr" defaultOpen>
    Combines column values within a group into a single *array* of those values, removing
    any duplicates.

    See [examples](/content/concepts/array#array-func-agg-ex-agg-dist).
  </Accordion>

  <Accordion title="UNNEST_JSON_ARRAY" id="unnest_json_array" defaultOpen>
    Transposes array values into columnar data.

    See [UNNEST\_JSON\_ARRAY](/content/concepts/array#array-func-unnest).
  </Accordion>
</AccordionGroup>

<a id="sql-conditional-functions" />

## Conditional Functions

Conditional functions are subject to
[short-circuiting](/content/concepts/expressions#short-circuiting) to aid in error-checking.

<AccordionGroup>
  <Accordion title="DECODE(expr, match_a, value_a, ..., match_N, value_N[, unmatched_value])" id="decode-expr-match_a-value_a-match_n-value_n-unmatched_value" defaultOpen>
    Evaluates `expr`: returns the first `value` whose corresponding `match` is equal to
    `expr`; returns the optional `unmatched_value` (or *null*), if no match is found
  </Accordion>

  <Accordion title="IF(expr, value_if_true, value_if_false)" id="if-expr-value_if_true-value_if_false" defaultOpen>
    Evaluates `expr`: if *true*, returns `value_if_true`; otherwise, if *false* or *null*,
    returns `value_if_false`

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Parameter</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>expr</code></td>
            <td>any *true*/*false* condition <Note>When an integer column is used directly, this function will interpret non-zero values as *true* and zero values as *false*.</Note></td>
          </tr>

          <tr>
            <td><code>value\_if\_true</code></td>
            <td>any type; must be the same type as <code>value\_if\_false</code></td>
          </tr>

          <tr>
            <td><code>value\_if\_false</code></td>
            <td>any type; must be the same type as <code>value\_if\_true</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>
</AccordionGroup>

### CASE

The case statement acts as a *scalar function*, but has two more complex forms.
Note that for each of these `CASE` statements, the value expressions must all
be of the same or convertible data type.

In the first form, each `WHEN` is followed by a conditional expression whose
corresponding `THEN` expression will have its value returned, if true.
Control will continue through each `WHEN` until a match is found and the
corresponding value returned; if no match is found, the value of the `ELSE`
expression will be returned, or *null*, if no `ELSE` clause exists.

```sql title="CASE without Expression Syntax" theme={null}
CASE
    WHEN <cond_expr_a> THEN <value_expr_a>
    ...
    WHEN <cond_expr_n> THEN <value_expr_n>
    ELSE <value_expr>
END
```

In the second form, the `CASE` expression is evaluated.  A match of that
result will be attempted against each `WHEN` expression until a match is found
and the value of the corresponding `THEN` expression returned; if no match is
found, the value of the `ELSE` expression will be returned, or *null*, if no
`ELSE` clause exists.

```sql title="CASE with Expression Syntax" theme={null}
CASE <expr>
    WHEN <match_expr_a> THEN <value_expr_a>
    ...
    WHEN <match_expr_n> THEN <value_expr_n>
    ELSE <value_expr>
END
```

<Info>
  This second version below has greater optimization than the first.
</Info>

```sql CASE without Expression Example theme={null}
CASE
    WHEN color = 1 THEN 'Red'
    WHEN color >= 2 THEN 'Green'
    ELSE 'Blue'
END
```

```sql CASE with Expression Example theme={null}
CASE MOD(LENGTH(text), 2)
    WHEN 0 THEN 'Even'
    WHEN 1 THEN 'Odd'
    ELSE null
END
```

<a id="sql-conversion-functions" />

## Conversion Functions

<AccordionGroup>
  <Accordion title="CAST (expr AS [SQL_]<conv_type>) *or* CONVERT (expr, [SQL_]<conv_type>)" id="cast-expr-as-sql_<conv_type>-or-convert-expr-sql_<conv_type>" defaultOpen>
    Converts `expr` into `conv_type` data type

    **Conversion Types**:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Numeric</th>
            <th>String</th>
            <th>Date/Time</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>BIGINT</code></td>
            <td><code>CHAR(N)</code></td>
            <td><code>DATE</code></td>
          </tr>

          <tr>
            <td><code>DECIMAL(P,S)</code></td>
            <td><code>VARCHAR(N)</code></td>
            <td><code>DATETIME</code></td>
          </tr>

          <tr>
            <td><code>DOUBLE</code></td>

            <td />

            <td><code>TIME</code></td>
          </tr>

          <tr>
            <td><code>FLOAT</code></td>

            <td />

            <td><code>TIMESTAMP</code></td>
          </tr>

          <tr>
            <td><code>INTEGER</code></td>

            <td />

            <td><code>TYPE\_DATE</code></td>
          </tr>

          <tr>
            <td><code>NUMERIC(P,S)</code></td>

            <td />

            <td><code>TYPE\_TIME</code></td>
          </tr>

          <tr>
            <td><code>REAL</code></td>

            <td />

            <td><code>TYPE\_TIMESTAMP</code></td>
          </tr>

          <tr>
            <td><code>SMALLINT</code></td>

            <td />

            <td />
          </tr>

          <tr>
            <td><code>TINYINT</code></td>

            <td />

            <td />
          </tr>

          <tr>
            <td><code>UNSIGNED</code> <code>BIGINT</code></td>

            <td />

            <td />
          </tr>
        </tbody>
      </table>
    </div>

    <Info>
      When using the `SQL_` prefix,
      `UNSIGNED BIGINT` becomes `SQL_UNSIGNED_BIGINT`
    </Info>
  </Accordion>

  <Accordion title="CHAR(expr)" id="char-expr" defaultOpen>
    Returns the character associated with the ASCII code
    given in `expr`
  </Accordion>

  <Accordion title="CHAR1(expr)" id="char1-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(1)` type
  </Accordion>

  <Accordion title="CHAR2(expr)" id="char2-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(2)` type
  </Accordion>

  <Accordion title="CHAR4(expr)" id="char4-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(4)` type
  </Accordion>

  <Accordion title="CHAR8(expr)" id="char8-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(8)` type
  </Accordion>

  <Accordion title="CHAR16(expr)" id="char16-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(16)` type
  </Accordion>

  <Accordion title="CHAR32(expr)" id="char32-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(32)` type
  </Accordion>

  <Accordion title="CHAR64(expr)" id="char64-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(64)` type
  </Accordion>

  <Accordion title="CHAR128(expr)" id="char128-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(128)` type
  </Accordion>

  <Accordion title="CHAR256(expr)" id="char256-expr" defaultOpen>
    Converts the given `expr` to `VARCHAR(256)` type
  </Accordion>

  <Accordion title="DATE(expr)" id="date-expr" defaultOpen>
    Converts `expr` to date (`YYYY-MM-DD`) format
  </Accordion>

  <Accordion title="DATETIME(expr)" id="datetime-expr" defaultOpen>
    Converts `expr` to datetime (`YYYY-MM-DD HH24:MI:SS.mmm`) format
  </Accordion>

  <Accordion title="DECIMAL(expr)" id="decimal-expr" defaultOpen>
    Converts the given `expr` to `DECIMAL` type
  </Accordion>

  <Accordion title="DOUBLE(expr)" id="double-expr" defaultOpen>
    Converts the given `expr` to `DOUBLE` type
  </Accordion>

  <Accordion title="FLOAT(expr)" id="float-expr" defaultOpen>
    Converts the given `expr` to `REAL` type
  </Accordion>

  <Accordion title="INT(expr)" id="int-expr" defaultOpen>
    Converts the given `expr` to `INTEGER` type
  </Accordion>

  <Accordion title="LONG(expr)" id="long-expr" defaultOpen>
    Converts the given `expr` to `BIGINT` type; if `expr` is a `TIMESTAMP` or
    `DATETIME` type, the value will be the number of milliseconds since the epoch
  </Accordion>

  <Accordion title="STRING(expr)" id="string-expr" defaultOpen>
    Converts `expr` to a string format appropriate for the `expr` type
  </Accordion>

  <Accordion title="TIME(expr)" id="time-expr" defaultOpen>
    Converts `expr` to time (`HH24:MI:SS`) format
  </Accordion>

  <Accordion title="TIMESTAMP(expr)" id="timestamp-expr" defaultOpen>
    Converts `expr` to `TIMESTAMP` type
  </Accordion>

  <Accordion title="TO_CHAR(expr, format)" id="to_char-expr-format" defaultOpen>
    Converts the given date/time `expr` to a string matching the given `format`.
    The returned string will be truncated at 32 characters.
    See [Date/Time Conversion Codes](/content/sql/query#sql-datetime-conversion-codes) for the list of format codes.

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>TO\_CHAR(DATETIME(971181296000), '"Last login: "YYYY-MM-DD')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>Last login: 2000-10-10</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="TO_DATE(string, format)" id="to_date-string-format" defaultOpen>
    Converts the given string to a *date* type with the given format code.
    See [Date/Time Conversion Codes](/content/sql/query#sql-datetime-conversion-codes) for the list of format codes.

    Example:

    ```
    TO_DATE('2017-06-15', 'YYYY-MM-DD')
    ```
  </Accordion>

  <Accordion title="TO_DATETIME(string, format)" id="to_datetime-string-format" defaultOpen>
    Converts the given string to a *datetime* type with the given format code.
    See [Date/Time Conversion Codes](/content/sql/query#sql-datetime-conversion-codes) for the list of format codes.

    Example:

    ```
    TO_DATETIME('2017-06-15 10:37:30', 'YYYY-MM-DD HH:MI:SS')
    ```
  </Accordion>

  <Accordion title="TO_TIME(string, format)" id="to_time-string-format" defaultOpen>
    Converts the given string to a *time* type with the given format code.
    See [Date/Time Conversion Codes](/content/sql/query#sql-datetime-conversion-codes) for the list of format codes.

    Example:

    ```
    TO_TIME('10:37:30', 'HH:MI:SS')
    ```
  </Accordion>

  <Accordion title="TO_TIMESTAMP(string, format)" id="to_timestamp-string-format" defaultOpen>
    Converts the given string to a *timestamp* type with the given format code.
    See [Date/Time Conversion Codes](/content/sql/query#sql-datetime-conversion-codes) for the list of format codes.

    Example:

    ```
    TO_TIMESTAMP('2017-06-15 10:37:30', 'YYYY-MM-DD HH:MI:SS')
    ```
  </Accordion>

  <Accordion title="ULONG(expr)" id="ulong-expr" defaultOpen>
    Converts the given `expr` to `UNSIGNED BIGINT` type
  </Accordion>

  <Accordion title="VECTOR(expr, len)" id="vector-expr-len" defaultOpen>
    Converts the given stringified array of `len` number of *float* values in `expr` to
    `VECTOR` type.

    Example:

    ```
    VECTOR('[1.1, 2.2, 3.3]', 3)
    ```
  </Accordion>
</AccordionGroup>

<a id="sql-datetime-conversion-codes" />

### Date/Time Conversion Codes

The following formatting codes can be used to convert date/time strings to
native date/time objects (with `TO_DATE`, `TO_DATETIME`, `TO_TIME` and `TO_TIMESTAMP`)
and for formatting date/time objects as strings (with `TO_CHAR`).

These characters are interpreted literally:  `-` `/` `,` `.` `;` `:`

Other characters need to be quoted in order to be interpreted literally.
For example, `MM-DD-YYYY` can be used to convert `01-02-2022` to a date,
while `"Today is "MM-DD-YYYY` is needed to convert `Today is 01-02-2022`.

In the following table, `Opt` in the Input column indicates that the field may be empty
when being read, and still be considered a valid input.  This can be useful when reading
data from a source that, for example, sometimes includes milliseconds in their time strings
and sometimes does not (e.g., the `MMM` code is `Opt`).  `Yes` in the Input column indicates
that some data must be present in the input string to be considered valid, unless it is after
a `$` character, in which case all input after the `$` is optional.

| Format Code | Input | Output | Description                                                                                                                                                                                                                                                                                                                      |
| ----------- | ----- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `_`         | Yes   |        | Any one character                                                                                                                                                                                                                                                                                                                |
| `?`         | Opt   |        | Zero or more non-digit characters                                                                                                                                                                                                                                                                                                |
| `$`         | Yes   |        | Everything after this is optional; e.g., `HH:MI$:SS` would accept `12:34` and `12:34:56`                                                                                                                                                                                                                                         |
| `AD`        |       | Yes    | Era indicator without periods                                                                                                                                                                                                                                                                                                    |
| `A.D.`      |       | Yes    | Era indicator with periods                                                                                                                                                                                                                                                                                                       |
| `AM`        | Yes   | Yes    | Meridian indicator without periods \[`AM`, `PM`]                                                                                                                                                                                                                                                                                 |
| `A.M.`      | Yes   | Yes    | Meridian indicator with periods \[`A.M.`, `P.M.`]                                                                                                                                                                                                                                                                                |
| `BC`        |       | Yes    | Era indicator without periods                                                                                                                                                                                                                                                                                                    |
| `B.C.`      |       | Yes    | Era indicator with periods                                                                                                                                                                                                                                                                                                       |
| `C`         | Yes   | Yes    | Number of day in calendar month, with optional leading zero \[`1` - `31`]                                                                                                                                                                                                                                                        |
| `CC`        |       | Yes    | Century (if last 2 digits of the 4-digit year are `00`, this is the first 2 digits; otherwise, this is first 2 digits + 1)                                                                                                                                                                                                       |
| `D`         | Yes   | Yes    | Day of week \[`1` - `7`] (*Sunday* - *Saturday*)                                                                                                                                                                                                                                                                                 |
| `DAY`       | Yes   | Yes    | Day of week \[`Sunday` - `Saturday`]                                                                                                                                                                                                                                                                                             |
| `DD`        | Yes   | Yes    | Number of day in month, with leading zero \[`01` - `31`]                                                                                                                                                                                                                                                                         |
| `DDD`       | Yes   | Yes    | Number of day of year \[`1` - `366`]                                                                                                                                                                                                                                                                                             |
| `DL`        | Yes   | Yes    | Date long format (`DAY, MONTH C, RRRR`)                                                                                                                                                                                                                                                                                          |
| `DS`        | Yes   | Yes    | Date short format (`M/C/RRRR`)                                                                                                                                                                                                                                                                                                   |
| `DY`        | Yes   | Yes    | Abbreviated day name (e.g., "Mon")                                                                                                                                                                                                                                                                                               |
| `FF[1-9]`   | Opt   | Yes    | Fractional seconds where the number of fractional second digits can be specified (default is 3 digits); when used for input, the string may contain an optional "." preceding the numbers                                                                                                                                        |
| `H`         | Yes   | Yes    | Alias for `H12`                                                                                                                                                                                                                                                                                                                  |
| `H12`       | Yes   | Yes    | Hour of day in 12-hour format, with optional leading zero \[`0` - `11`]                                                                                                                                                                                                                                                          |
| `H24`       | Yes   | Yes    | Hour of day in 24-hour format, with optional leading zero \[`0` - `23`]                                                                                                                                                                                                                                                          |
| `HH`        | Yes   | Yes    | Alias for `HH12`                                                                                                                                                                                                                                                                                                                 |
| `HH12`      | Yes   | Yes    | Hour of day in 12-hour format, with leading zero \[`00` - `11`]                                                                                                                                                                                                                                                                  |
| `HH24`      | Yes   | Yes    | Hour of day in 24-hour format, with leading zero \[`00` - `23`]                                                                                                                                                                                                                                                                  |
| `I`         | Yes   | Yes    | Last digit of ISO year                                                                                                                                                                                                                                                                                                           |
| `ID`        | Yes   | Yes    | ISO 8601 day of week \[`1` - `7`] (*Monday* - *Sunday*)                                                                                                                                                                                                                                                                          |
| `IDDD`      | Yes   | Yes    | ISO 8601 day of year \[`001` - `371`] (where `001` is the *Monday* of the 1st ISO week)                                                                                                                                                                                                                                          |
| `IW`        | Yes   | Yes    | ISO 8601 week of year \[`01` - `53`] (where `01` contains the first *Thursday* of the year)                                                                                                                                                                                                                                      |
| `IY`        | Yes   | Yes    | Last 2 digits of ISO year                                                                                                                                                                                                                                                                                                        |
| `IYY`       | Yes   | Yes    | Last 3 digits of ISO year                                                                                                                                                                                                                                                                                                        |
| `IYYY`      | Yes   | Yes    | Last 4 digits of ISO year                                                                                                                                                                                                                                                                                                        |
| `J`         | Yes   | Yes    | Julian day; the number of days since *January 1, 4712 BC*.  Number specified with `J` must be integers.                                                                                                                                                                                                                          |
| `LLL`       | Opt   | Yes    | Whole milliseconds (often positioned after a colon); e.g., `12:34:56:78` => *78 milliseconds*; when used for input, the string may contain an optional "." or ":" preceding the numbers; when "." is found, this code will act like the `MMM` code                                                                               |
| `M`         | Yes   | Yes    | Number of month in year, with optional leading zero \[`1` - `12`]                                                                                                                                                                                                                                                                |
| `MI`        | Yes   | Yes    | Minute of hour \[`00` - `59`]                                                                                                                                                                                                                                                                                                    |
| `MM`        | Yes   | Yes    | Number of month in year, with leading zero \[`01` - `12`]                                                                                                                                                                                                                                                                        |
| `MMM`       | Opt   | Yes    | Fractions of a second up to milliseconds; e.g., `12:34:56.78` => *780 milliseconds*; when used for input, the string may contain an optional "." or ":" preceding the numbers; when ":" is found, this code will act like the `LLL` code                                                                                         |
| `MON`       | Yes   | Yes    | 3-character abbreviation of month in title case \[`Jan` - `Dec`]                                                                                                                                                                                                                                                                 |
| `MONTH`     | Yes   | Yes    | Full name of month \[`January` - `December`]                                                                                                                                                                                                                                                                                     |
| `MS`        | Opt   | Yes    | Alias for `MMM`                                                                                                                                                                                                                                                                                                                  |
| `OF`        | Opt   | Yes    | Time-zone offset from UTC (`TZHTZM`)                                                                                                                                                                                                                                                                                             |
| `PM`        | Yes   | Yes    | Alias for `AM`                                                                                                                                                                                                                                                                                                                   |
| `P.M.`      | Yes   | Yes    | Alias for `A.M.`                                                                                                                                                                                                                                                                                                                 |
| `Q`         |       | Yes    | Quarter of the year \[`1` - `4`] (*January-March* - *October-December*)                                                                                                                                                                                                                                                          |
| `RM`        | Yes   | Yes    | Roman numeral month \[`I` - `XII`] (*January* - *December*)                                                                                                                                                                                                                                                                      |
| `RR`        | Yes   | Yes    | Rounded year.  Assume the given 2-digit year occurs in the present century, then: <br /> <br /> \* If the assumed date is greater than 50 years into the future, declare the date to be in the previous century <br /> \* If the assumed date is greater than 50 years into the past, declare the date to be in the next century |
| `RRRR`      | Yes   | Yes    | Either a 2-digit or 4-digit year; if 2-digit, equivalent to `RR`                                                                                                                                                                                                                                                                 |
| `SCC`       |       | Yes    | Same as `CC`                                                                                                                                                                                                                                                                                                                     |
| `SS`        | Yes   | Yes    | Second of minute \[`00` - `59`]                                                                                                                                                                                                                                                                                                  |
| `SSSS`      | Yes   | Yes    | Alias for `SSSSS`                                                                                                                                                                                                                                                                                                                |
| `SSSSS`     | Yes   | Yes    | Seconds past midnight \[`0` - `86399`]                                                                                                                                                                                                                                                                                           |
| `SYEAR`     |       | Yes    | Same as `YEAR`                                                                                                                                                                                                                                                                                                                   |
| `SYYYY`     | Yes   | Yes    | Same as `YYYY`                                                                                                                                                                                                                                                                                                                   |
| `TS`        | Yes   | Yes    | Time short format (`H24:MI:SS.MMM`)                                                                                                                                                                                                                                                                                              |
| `TZ`        | Opt   | Yes    | Time zone (`TZH`)                                                                                                                                                                                                                                                                                                                |
| `TZH`       | Opt   | Yes    | Time zone hour (ISO); "Z" or +/- followed by one or two digits (will always output "Z")                                                                                                                                                                                                                                          |
| `TZM`       | Opt   | Yes    | Time zone minute (ISO); colon followed by one or two digits; for input, an optional colon is allowed at the front; if present, two digits must follow it                                                                                                                                                                         |
| `US`        | Opt   | Yes    | Microseconds; when used for input, the string may contain an optional "." preceding the numbers                                                                                                                                                                                                                                  |
| `W`         | Yes   | Yes    | Week of month \[`1` - `5`], where week 1 starts on the first day of the month and ends on the seventh                                                                                                                                                                                                                            |
| `WW`        | Yes   | Yes    | Week of year \[`1` - `53`], where week 1 starts on the first day of the year and continues to the seventh day of the year                                                                                                                                                                                                        |
| `X`         | Yes   | Yes    | Local radix character (always `.`.  E.g., `HH:MI:SSXFF`)                                                                                                                                                                                                                                                                         |
| `Y`         | Yes   | Yes    | Last 1 digit of year                                                                                                                                                                                                                                                                                                             |
| `Y,YYY`     | Yes   | Yes    | Year with a comma after the thousands place                                                                                                                                                                                                                                                                                      |
| `YEAR`      |       | Yes    | Year spelled out (e.g., "Two Thousand Twenty Five")                                                                                                                                                                                                                                                                              |
| `YY`        | Yes   | Yes    | Last 2 digits of year                                                                                                                                                                                                                                                                                                            |
| `YYY`       | Yes   | Yes    | Last 3 digits of year                                                                                                                                                                                                                                                                                                            |
| `YYYY`      | Yes   | Yes    | 4-digit year                                                                                                                                                                                                                                                                                                                     |

<a id="sql-datetime-functions" />

## Date/Time Functions

This section comprises the following functions:

* [Date/Time Base Functions](/content/sql/query#sql-datetime-functions-base), which can extract parts of
  date/time expressions, convert back and forth between data types, and return
  the current date/time
* [Date/Time Complex Conversion Functions](/content/sql/query#sql-datetime-functions-complex), which can perform more complex
  date/type conversions

<a id="sql-datetime-functions-base" />

### Date/Time Base Functions

<AccordionGroup>
  <Accordion title="CLOCK_TIMESTAMP()" id="clock_timestamp" defaultOpen>
    Returns the date & time as `YYYY-MM-DD HH24:MI:SS.mmm`

    <Info>
      `CLOCK_TIMESTAMP` may return different values each time it is called in the
      same query or SQL Procedure, which may lead to data getting out of sync across HA
      clusters.  Use `CURRENT_DATETIME` to avoid this issue.
    </Info>
  </Accordion>

  <Accordion title="CURRENT_DATE()" id="current_date" defaultOpen>
    Returns the date as `YYYY-MM-DD`
  </Accordion>

  <Accordion title="CURRENT_DATETIME()" id="current_datetime" defaultOpen>
    Returns the date & time as `YYYY-MM-DD HH24:MI:SS.mmm`

    <Info>
      `CURRENT_DATETIME` will return same values each time it is called in the
      same query or SQL Procedure, and should keep data in-sync across HA clusters.
      See `CLOCK_TIMESTAMP` to always get the actual time each time it is called.
    </Info>
  </Accordion>

  <Accordion title="CURRENT_TIME()" id="current_time" defaultOpen>
    Returns the time as `HH24:MI:SS.mmm`
  </Accordion>

  <Accordion title="CURRENT_TIMESTAMP()" id="current_timestamp" defaultOpen>
    Returns the date & time as `YYYY-MM-DD HH24:MI:SS.mmm`; to
    return the date & time as the number of milliseconds since the
    epoch, pass the result of this function to `LONG()`
  </Accordion>

  <Accordion title="DATEADD (unit, amount, expr)" id="dateadd-unit-amount-expr" defaultOpen>
    Adds the positive or negative integral `amount` of `unit` date/time intervals to the date/time in
    `expr`

    The following date/time intervals are supported for `unit`:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Constant</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>YEAR</code></td>
            <td>Year is modified by interval amount *(not affected by leap year, etc.)*</td>
          </tr>

          <tr>
            <td><code>QUARTER</code></td>
            <td>Month is modified by three times the interval amount, irrespective of the number of days in the months between; day adjusting performed the same as the <code>MONTH</code> description, but only on final month (e.g., *Jan 31st* + *1 quarter* will be *Apr 30th*, not *Apr 28th* because of *February*)</td>
          </tr>

          <tr>
            <td><code>MONTH</code></td>
            <td>Month is modified by interval amount and date adjusted if overflow/underflow occurs; day adjusted to last day of calculated month if not a valid day for that month *(e.g. Apr 31st -> Apr 30th)*</td>
          </tr>

          <tr>
            <td><code>WEEK</code></td>
            <td>Day is modified by 7 times the interval amount *(time not* *affected by daylight savings time, etc.);* month & year are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>DAY</code></td>
            <td>Day is modified by interval amount *(time not affected by daylight* *savings time, etc.);* date is adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>HOUR</code></td>
            <td>Hour is modified by interval amount *(time not affected by daylight* *savings time, etc.);* date is adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>MINUTE</code></td>
            <td>Minute is modified by interval amount; date/time are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>SECOND</code></td>
            <td>Second is modified by interval amount; date/time are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>MILLISECOND</code></td>
            <td>Millisecond is modified by interval amount; date/time are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>FRAC\_SECOND</code></td>
            <td>Nanosecond is modified by interval amount; date/time are adjusted, if overflow/underflow occurs <Note>Time is processed to millisecond precision, so any portion of an `amount` with finer granularity than 1,000,000 nanoseconds will be ignored (e.g., requesting the addition of *1,234,567* *nanoseconds* will result in *1 millisecond* actually being added)</Note></td>
          </tr>
        </tbody>
      </table>
    </div>

    <Info>
      Any of these `unit` types can have a `SQL_TSI_` prefix prepended to them; e.g., both
      `DAY` and `SQL_TSI_DAY` are valid `unit` types for specifying a day interval.
    </Info>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>DATEADD(YEAR, 1, '2000-10-10')</code></td>
            <td><code>2001-10-10</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(QUARTER, 1, '2000-11-30')</code></td>
            <td><code>2001-02-28</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(MONTH, 1, '2000-01-31')</code></td>
            <td><code>2000-02-29</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(WEEK, 53, '2000-01-01')</code></td>
            <td><code>2001-01-06</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(DAY, 1, '2000-12-31')</code></td>
            <td><code>2001-01-01</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(HOUR, 12, '2000-10-10 12:34:56')</code></td>
            <td><code>2000-10-11 00:34:56.000</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(MINUTE, 1, '2000-10-10 12:34:56')</code></td>
            <td><code>2000-10-10 12:35:56.000</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(SECOND, 1, '2000-12-31 23:59:59')</code></td>
            <td><code>2001-01-01 00:00:00.000</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(MILLISECOND, 1, '2000-10-10 12:34:56')</code></td>
            <td><code>2000-10-10 12:34:56.001</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(FRAC\_SECOND, 1000000, '2000-10-10 12:34:56')</code></td>
            <td><code>2000-10-10 12:34:56.001</code></td>
          </tr>

          <tr>
            <td><code>DATEADD(SECOND, 1, TIME '12:34:56')</code></td>
            <td><code>12:34:57.000</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="DATE_BUCKET (width, ds[, offset[, base]])" id="date_bucket-width-ds-offset-base" defaultOpen>
    Calculates the date range in which a given date `ds` falls, based on a set of fixed-width "buckets"
    with the given `width`, start-aligned `base` date, and `offset` from that `base` date.

    The `width` is the number of days each bucket should span.

    The `offset` is the number of days after (positive `offset`) or number of days before (negative
    `offset`) the `base` date to which the buckets should be aligned.  The default is no offset.

    The default `base` is `2000-01-03`.

    Typically, `DATE_BUCKET` is used in the following type of query:

    ```
    SELECT
        DATE_BUCKET(7, ds, -3, '2023-02-21')
            + INTERVAL 3 DAYS AS week_midpoint,
        AVG(cpu) AS avg_cpu
    FROM example.host_metrics_summary
    GROUP BY week_midpoint
    ORDER BY week_midpoint
    ```

    The result will be as follows:

    * Dates in the `ds` column of the `example.host_metrics_summary` table will be grouped into buckets
    * Each bucket will span a range of `7` days
    * The baseline bucket will start at `2023-02-18` (`2023-02-21` offset by `-3` days) and continue
      through `2023-02-24` (`7` days, including `2023-02-18`)
    * Buckets will extend before & after the baseline bucket in contiguous, non-overlapping fashion
    * Each result record will show the date in the middle of the bucket's date range (`+ INTERVAL 3 DAYS`
      from the start of each `7` day span) and the average CPU usage across the records contained within
      that date range
    * Gaps in the data will not be filled in with empty buckets--only buckets containing the dates found in
      the `ds` column of `example.host_metrics_summary` will be returned in the result set
  </Accordion>

  <Accordion title="DATEDIFF ([unit,] begin, end)" id="datediff-unit-begin-end" defaultOpen>
    Calculates the difference between two date/time expressions, returning the result as an
    integral difference in the units specified; more precisely, how many whole date/time
    intervals of type `unit` need to be added to  (or subtracted from) `begin` to equal
    `end` (or get as close as possible **without** going past it) using the unit types and
    and rules specified in `DATEADD`.

    The default `unit` is `DAY`.

    <Info>
      This *is not* symmetric with `DATEADD` in all cases, as adding *1*
      `MONTH` to *Mar 31st* results in *Apr 30th*, but the `DATEDIFF` in `MONTH`
      units between those two dates is *0*.
    </Info>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>DATEDIFF(DATE('2000-10-10'), DATE('2000-12-31'))</code></td>
            <td><code>82</code></td>
          </tr>

          <tr>
            <td><code>DATEDIFF(DATE('2000-03-31'), DATE('2000-04-30'))</code></td>
            <td><code>30</code></td>
          </tr>

          <tr>
            <td><code>DATEDIFF(DATE('2000-12-31'), DATE('2000-10-10'))</code></td>
            <td><code>-82</code></td>
          </tr>

          <tr>
            <td><code>DATEDIFF(DATETIME('2000-10-10 12:34:56'), 978222896000)</code></td>
            <td><code>81</code></td>
          </tr>

          <tr>
            <td><code>DATEDIFF(MONTH, DATE('2000-10-10'), DATE('2000-12-31'))</code></td>
            <td><code>2</code></td>
          </tr>

          <tr>
            <td><code>DATEDIFF(MONTH, DATE('2000-03-31'), DATE('2000-04-30'))</code></td>
            <td><code>0</code></td>
          </tr>

          <tr>
            <td><code>DATEDIFF(MONTH, DATE('2000-12-31'), DATE('2000-10-10'))</code></td>
            <td><code>-2</code></td>
          </tr>

          <tr>
            <td><code>DATEDIFF(HOUR, DATETIME('2000-10-10 12:34:56'), 978222896000)</code></td>
            <td><code>1956</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="DATEPART(part, expr)" id="datepart-part-expr" defaultOpen>
    Returns the requested `part` of the date/time `expr`.  The `part` may be any of
    those specified in `DATE_TRUNC(part, expr)`, plus the following:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Constant</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>SECS\_SINCE\_EPOCH</code></td>
            <td>Return the number of seconds since the epoch (1970-01-01).</td>
          </tr>

          <tr>
            <td><code>MSECS\_SINCE\_EPOCH</code></td>
            <td>Return the number of milliseconds since the epoch.</td>
          </tr>
        </tbody>
      </table>
    </div>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>DATEPART(YEAR, '2000-12-31')</code></td>
            <td><code>2000</code></td>
          </tr>

          <tr>
            <td><code>DATEPART(MONTH, '2000-03-31 12:34:56.000')</code></td>
            <td><code>3</code></td>
          </tr>

          <tr>
            <td><code>DATEPART(DAY, '2000-03-31 12:34:56.000')</code></td>
            <td><code>31</code></td>
          </tr>

          <tr>
            <td><code>DATEPART(SECOND, '2000-03-31 12:34:56.220')</code></td>
            <td><code>56</code></td>
          </tr>

          <tr>
            <td><code>DATEPART(MSECS\_SINCE\_EPOCH, '2000-03-31 12:34:56.220')</code></td>
            <td><code>954506096220</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="DATE_TRUNC(part, expr)" id="date_trunc-part-expr" defaultOpen>
    Returns the date/time `expr` after truncating it beyond the given date/time `part`.
    The following date/time constants are supported for `part`:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Constant</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>YEAR</code></td>
            <td>Return the first day of the year in which <code>expr</code> occurs</td>
          </tr>

          <tr>
            <td><code>QUARTER</code></td>
            <td>Return the first day of the quarter in which <code>expr</code> occurs</td>
          </tr>

          <tr>
            <td><code>MONTH</code></td>
            <td>Return the first day of the month in which <code>expr</code> occurs</td>
          </tr>

          <tr>
            <td><code>WEEK</code></td>
            <td>Return the first day of the week in which <code>expr</code> occurs</td>
          </tr>

          <tr>
            <td><code>DAY</code></td>
            <td>Return the date (at midnight) on which <code>expr</code> occurs</td>
          </tr>

          <tr>
            <td><code>HOUR</code></td>
            <td>Return the timestamp up to the hour in which <code>expr</code> occurs</td>
          </tr>

          <tr>
            <td><code>MINUTE</code></td>
            <td>Return the timestamp up to the minute in which <code>expr</code> occurs</td>
          </tr>

          <tr>
            <td><code>SECOND</code></td>
            <td>Return the timestamp up to the second in which <code>expr</code> occurs</td>
          </tr>

          <tr>
            <td><code>MILLISECOND</code></td>
            <td>Return the timestamp up to the millisecond in which <code>expr</code> occurs</td>
          </tr>
        </tbody>
      </table>
    </div>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>DATE\_TRUNC(YEAR, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-01-01 00:00:00.000</code></td>
          </tr>

          <tr>
            <td><code>DATE\_TRUNC(QUARTER, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-07-01 00:00:00.000</code></td>
          </tr>

          <tr>
            <td><code>DATE\_TRUNC(MONTH, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-09-01 00:00:00.000</code></td>
          </tr>

          <tr>
            <td><code>DATE\_TRUNC(WEEK, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-09-07 00:00:00.000</code></td>
          </tr>

          <tr>
            <td><code>DATE\_TRUNC(DAY, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-09-10 00:00:00.000</code></td>
          </tr>

          <tr>
            <td><code>DATE\_TRUNC(HOUR, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-09-10 12:00:00.000</code></td>
          </tr>

          <tr>
            <td><code>DATE\_TRUNC(MINUTE, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-09-10 12:34:00.000</code></td>
          </tr>

          <tr>
            <td><code>DATE\_TRUNC(SECOND, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-09-10 12:34:56.000</code></td>
          </tr>

          <tr>
            <td><code>DATE\_TRUNC(MILLISECOND, '2008-09-10 12:34:56.789')</code></td>
            <td><code>2008-09-10 12:34:56.789</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="DAY(expr)" id="day-expr" defaultOpen>
    Alias for `DAYOFMONTH(expr)`
  </Accordion>

  <Accordion title="DAYNAME(expr)" id="dayname-expr" defaultOpen>
    Extracts the day of the week from `expr` and converts it to the
    corresponding day name \[`Sunday` - `Saturday` ]
  </Accordion>

  <Accordion title="DAYOFMONTH(expr)" id="dayofmonth-expr" defaultOpen>
    Extracts the day of the month from `expr` \[`1` - `31`]
  </Accordion>

  <Accordion title="DAYOFWEEK(expr)" id="dayofweek-expr" defaultOpen>
    Extracts the day of the week from `expr` \[`1` - `7`]

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Expression Value</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td>Date on *Sunday*</td>
            <td><code>1</code></td>
          </tr>

          <tr>
            <td>Date on *Monday*</td>
            <td><code>2</code></td>
          </tr>

          <tr>
            <td>Date on *Tuesday*</td>
            <td><code>3</code></td>
          </tr>

          <tr>
            <td>Date on *Wednesday*</td>
            <td><code>4</code></td>
          </tr>

          <tr>
            <td>Date on *Thursday*</td>
            <td><code>5</code></td>
          </tr>

          <tr>
            <td>Date on *Friday*</td>
            <td><code>6</code></td>
          </tr>

          <tr>
            <td>Date on *Saturday*</td>
            <td><code>7</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="DAY_OF_WEEK(expr)" id="day_of_week-expr" defaultOpen>
    Alias for `DAYOFWEEK(expr)`
  </Accordion>

  <Accordion title="DAYOFYEAR(expr)" id="dayofyear-expr" defaultOpen>
    Extracts the day of the year from `expr` \[`1` - `366`]
  </Accordion>

  <Accordion title="DAY_OF_YEAR(expr)" id="day_of_year-expr" defaultOpen>
    Alias for `DAYOFYEAR(expr)`
  </Accordion>

  <Accordion title="EPOCH_MSECS_TO_DATETIME(expr)" id="epoch_msecs_to_datetime-expr" defaultOpen>
    Converts `expr` milliseconds since the epoch to a date/time

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>EPOCH\_MSECS\_TO\_DATETIME(971181296789)</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>2000-10-10 12:34:56.789</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="EPOCH_SECS_TO_DATETIME(expr)" id="epoch_secs_to_datetime-expr" defaultOpen>
    Converts `expr` seconds since the epoch to a date/time

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>EPOCH\_SECS\_TO\_DATETIME(971181296)</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>2000-10-10 12:34:56.000</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="EXTRACT(<part> FROM <expr>)" id="extract-<part>-from-<expr>" defaultOpen>
    Extracts the date/time `part` from the date/time `expr`.  This function is used to support database
    clients which require the call in this form; however, each of the supported date/time `part`
    constants results in a call for which there is a simpler, more direct corresponding call, which are
    listed below.

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Constant</th>
            <th>Corresponding Alternative Function Call</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>YEAR</code></td>
            <td><code>YEAR(expr)</code></td>
          </tr>

          <tr>
            <td><code>QUARTER</code></td>
            <td><code>QUARTER(expr)</code></td>
          </tr>

          <tr>
            <td><code>MONTH</code></td>
            <td><code>MONTH(expr)</code></td>
          </tr>

          <tr>
            <td><code>WEEK</code></td>
            <td><code>WEEK(expr)</code></td>
          </tr>

          <tr>
            <td><code>DAY</code></td>
            <td><code>DAY(expr)</code></td>
          </tr>

          <tr>
            <td><code>HOUR</code></td>
            <td><code>HOUR(expr)</code></td>
          </tr>

          <tr>
            <td><code>MINUTE</code></td>
            <td><code>MINUTE(expr)</code></td>
          </tr>

          <tr>
            <td><code>SECOND</code></td>
            <td><code>SECOND(expr)</code></td>
          </tr>

          <tr>
            <td><code>MILLISECOND</code></td>
            <td><code>MSEC(expr)</code></td>
          </tr>

          <tr>
            <td><code>EPOCH</code></td>
            <td><code>SECS\_SINCE\_EPOCH(expr)</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="HOUR(expr)" id="hour-expr" defaultOpen>
    Extracts the hour of the day from `expr` \[`0` - `23`]
  </Accordion>

  <Accordion title="<expr> + INTERVAL '<amount>' <part> <expr> - INTERVAL '<amount>' <part>" id="<expr>-interval-<amount>-<part>-<expr>-interval-<amount>-<part>" defaultOpen>
    Adds to or subtracts from the date/time `expr` the integral
    `amount` units of type `part`.  This mirrors the behavior of
    the `TIMESTAMPADD` function, only with a different format and
    different date/time part constants.  The following date/time
    constants are supported for `part`:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Constant</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>YEAR</code></td>
            <td>Year is modified by interval amount *(not affected by leap year, etc.)*</td>
          </tr>

          <tr>
            <td><code>QUARTER</code></td>
            <td>Month is modified by three times the interval amount, irrespective of the number of days in the months between; day adjusting performed the same as the <code>MONTH</code> description, but only on final month (e.g., *Jan 31st* + *1 quarter* will be *Apr 30th*, not *Apr 28th* because of *February*)</td>
          </tr>

          <tr>
            <td><code>MONTH</code></td>
            <td>Month is modified by interval amount and date adjusted if overflow/underflow occurs; day adjusted to last day of calculated month if not a valid day for that month *(e.g. Apr 31st -> Apr 30th)*</td>
          </tr>

          <tr>
            <td><code>WEEK</code></td>
            <td>Day is modified by 7 times the interval amount *(time not* *affected by daylight savings time, etc.);* month & year are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>DAY</code></td>
            <td>Day is modified by interval amount *(time not affected by daylight* *savings time, etc.);* date is adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>HOUR</code></td>
            <td>Hour is modified by interval amount *(time not affected by daylight* *savings time, etc.);* date is adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>MINUTE</code></td>
            <td>Minute is modified by interval amount; date/time are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>SECOND</code></td>
            <td>Second is modified by interval amount; date/time are adjusted, if overflow/underflow occurs</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="LAST_DAY(date)" id="last_day-date" defaultOpen>
    Returns the date of the last day of the month in the given `date`
  </Accordion>

  <Accordion title="MINUTE(expr)" id="minute-expr" defaultOpen>
    Extracts the minute of the day from `expr` \[`0` - `59`]
  </Accordion>

  <Accordion title="MONTH(expr)" id="month-expr" defaultOpen>
    Extracts the month of the year from `expr` \[`1` - `12`]
  </Accordion>

  <Accordion title="MONTHNAME(expr)" id="monthname-expr" defaultOpen>
    Extracts the month of the year from `expr` and converts it to
    the corresponding month name \[`January` - `December`]
  </Accordion>

  <Accordion title="MSEC(expr)" id="msec-expr" defaultOpen>
    Extracts the millisecond of the second from `expr` \[`0` - `999`]
  </Accordion>

  <Accordion title="MSECS_SINCE_EPOCH(expr)" id="msecs_since_epoch-expr" defaultOpen>
    Converts `expr` date/time to the number of milliseconds since the epoch

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>MSECS\_SINCE\_EPOCH('2000-10-10 12:34:56.789')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>971181296789</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="NEXT_DAY(date, day_of_week)" id="next_day-date-day_of_week" defaultOpen>
    Returns the date of the next day of the week, provided as a day
    name in `day_of_week`, that occurs after the given `date`

    Some examples, given that *2000-10-10* is a *Tuesday*:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>NEXT\_DAY('2000-10-10', 'Wednesday')</code></td>
            <td><code>2000-10-11</code></td>
          </tr>

          <tr>
            <td><code>NEXT\_DAY('2000-10-10', 'Friday')</code></td>
            <td><code>2000-10-13</code></td>
          </tr>

          <tr>
            <td><code>NEXT\_DAY('2000-10-10', 'Tuesday')</code></td>
            <td><code>2000-10-17</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="NOW()" id="now" defaultOpen>
    Alias for `CURRENT_DATETIME()`
  </Accordion>

  <Accordion title="QUARTER(expr)" id="quarter-expr" defaultOpen>
    Extracts the quarter of the year from `expr` \[`1` - `4`]

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Expression Value</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td>Date in *January*, *February*, or *March*</td>
            <td><code>1</code></td>
          </tr>

          <tr>
            <td>Date in *April*, *May*, or *June*</td>
            <td><code>2</code></td>
          </tr>

          <tr>
            <td>Date in *July*, *August*, or *September*</td>
            <td><code>3</code></td>
          </tr>

          <tr>
            <td>Date in *October*, *November*, or *December*</td>
            <td><code>4</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="SECOND(expr)" id="second-expr" defaultOpen>
    Extracts the seconds of the minute from `expr` \[`0` - `59`]
  </Accordion>

  <Accordion title="SEC(expr)" id="sec-expr" defaultOpen>
    Alias for `SECOND(expr)`
  </Accordion>

  <Accordion title="SECS_SINCE_EPOCH(expr)" id="secs_since_epoch-expr" defaultOpen>
    Converts `expr` date/time to the number of seconds since the epoch

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>SECS\_SINCE\_EPOCH('2000-10-10 12:34:56')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>971181296</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="SLEEP(expr)" id="sleep-expr" defaultOpen>
    Pause execution for at least `expr` seconds; though system load may delay the return from this call
    for longer than the specified amount.  Use a decimal for `expr` to pause for less than a second;
    e.g., `SLEEP(0.001)` will pause for at least 1 millisecond.  `SLEEP` should be invoked in a
    [Tableless Query](/content/sql/query#sql-tableless-query) to avoid being called for every record in a result set; e.g.:

    ```
    SELECT SLEEP(0.001)
    ```
  </Accordion>

  <Accordion title="TIME_BUCKET (width, ts[, offset[, base]])" id="time_bucket-width-ts-offset-base" defaultOpen>
    Calculates the date/time range in which a given timestamp `ts` falls, based on a set of fixed-width
    "buckets" with the given `width`, start-aligned `base` date/time, and `offset` from that `base`
    date/time

    The `width` is the number of milliseconds each bucket should span.  An `INTERVAL` can also be used
    to specify the `width`.

    The `offset` is the number of milliseconds after (positive `offset`) or number of milliseconds
    before (negative `offset`) the `base` date/time to which the buckets should be aligned.  An
    `INTERVAL` can also be used to specify the `offset`.  The default is no offset.

    The default `base` is `2000-01-03 00:00:00`.

    Typically, `TIME_BUCKET` is used in the following type of query:

    ```
    SELECT
        TIME_BUCKET(
            INTERVAL 5 MINUTES,
            ts,
            INTERVAL -2.5 MINUTES,
            '2023-02-28'
        ) + INTERVAL 2.5 MINUTES AS five_minute_midpoint,
        AVG(cpu) AS avg_cpu
    FROM example.host_metrics
    GROUP BY five_minute_midpoint
    ORDER BY five_minute_midpoint
    ```

    The result will be as follows:

    * Timestamps in the `ts` column of the `example.host_metrics` table will be grouped into buckets
    * Each bucket will span a `5` minute interval
    * The baseline bucket will start at `2023-02-27 23:57:30` (`2023-02-28` offset by `-2.5` minutes)
      and continue through `2023-02-28 00:02:30` (`5` minutes from `2023-02-27 23:57:30`)
    * Buckets will extend before & after the baseline bucket in contiguous, non-overlapping fashion
    * Each result record will show the timestamp in the middle of the bucket's range
      (`+ INTERVAL 2.5 MINUTES` from the start of each `5` minute span) and the average CPU usage
      across the records contained within that date/time range
    * Gaps in the data will not be filled in with empty buckets--only buckets containing the timestamps
      found in the `ts` column of `example.host_metrics` will be returned in the result set
  </Accordion>

  <Accordion title="TIMESTAMPADD (unit, amount, expr)" id="timestampadd-unit-amount-expr" defaultOpen>
    Adds the positive or negative integral `amount` of `unit` date/time intervals to the date/time in
    `expr`

    The following date/time intervals are supported for `unit`:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Constant</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>YEAR</code></td>
            <td>Year is modified by interval amount *(not affected by leap year, etc.)*</td>
          </tr>

          <tr>
            <td><code>QUARTER</code></td>
            <td>Month is modified by three times the interval amount, irrespective of the number of days in the months between; day adjusting performed the same as the <code>MONTH</code> description, but only on final month (e.g., *Jan 31st* + *1 quarter* will be *Apr 30th*, not *Apr 28th* because of *February*)</td>
          </tr>

          <tr>
            <td><code>MONTH</code></td>
            <td>Month is modified by interval amount and date adjusted if overflow/underflow occurs; day adjusted to last day of calculated month if not a valid day for that month *(e.g. Apr 31st -> Apr 30th)*</td>
          </tr>

          <tr>
            <td><code>WEEK</code></td>
            <td>Day is modified by 7 times the interval amount *(time not* *affected by daylight savings time, etc.);* month & year are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>DAY</code></td>
            <td>Day is modified by interval amount *(time not affected by daylight* *savings time, etc.);* date is adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>HOUR</code></td>
            <td>Hour is modified by interval amount *(time not affected by daylight* *savings time, etc.);* date is adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>MINUTE</code></td>
            <td>Minute is modified by interval amount; date/time are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>SECOND</code></td>
            <td>Second is modified by interval amount; date/time are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>MILLISECOND</code></td>
            <td>Millisecond is modified by interval amount; date/time are adjusted, if overflow/underflow occurs</td>
          </tr>

          <tr>
            <td><code>FRAC\_SECOND</code></td>
            <td>Nanosecond is modified by interval amount; date/time are adjusted, if overflow/underflow occurs <Note>Time is processed to millisecond precision, so any portion of an `amount` with finer granularity than 1,000,000 nanoseconds will be ignored (e.g., requesting the addition of *1,234,567* *nanoseconds* will result in *1 millisecond* actually being added)</Note></td>
          </tr>
        </tbody>
      </table>
    </div>

    <Info>
      Any of these `unit` types can have a `SQL_TSI_` prefix prepended to them; e.g., both
      `DAY` and `SQL_TSI_DAY` are valid `unit` types for specifying a day interval.
    </Info>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_YEAR, 1, '2000-10-10')</code></td>
            <td><code>2001-10-10</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_QUARTER, 1, '2000-11-30')</code></td>
            <td><code>2001-02-28</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_MONTH, 1, '2000-01-31')</code></td>
            <td><code>2000-02-29</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_WEEK, 53, '2000-01-01')</code></td>
            <td><code>2001-01-06</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_DAY, 1, '2000-12-31')</code></td>
            <td><code>2001-01-01</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_HOUR, 12, '2000-10-10 12:34:56')</code></td>
            <td><code>2000-10-11 00:34:56.000</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_MINUTE, 1, '2000-10-10 12:34:56')</code></td>
            <td><code>2000-10-10 12:35:56.000</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_SECOND, 1, '2000-12-31 23:59:59')</code></td>
            <td><code>2001-01-01 00:00:00.000</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_MILLISECOND, 1, '2000-10-10 12:34:56')</code></td>
            <td><code>2000-10-10 12:34:56.001</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_FRAC\_SECOND, 1000000, '2000-10-10 12:34:56')</code></td>
            <td><code>2000-10-10 12:34:56.001</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPADD(SQL\_TSI\_SECOND, 1, TIME '12:34:56')</code></td>
            <td><code>12:34:57.000</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="TIMESTAMPDIFF (unit, begin, end)" id="timestampdiff-unit-begin-end" defaultOpen>
    Calculates the difference between two date/time expressions, returning the result as an
    integral difference in the units specified; more precisely, how many whole date/time
    intervals of type `unit` need to be added to  (or subtracted from) `begin` to equal
    `end` (or get as close as possible **without** going past it) using the unit types and
    and rules specified in `TIMESTAMPADD`.

    <Info>
      This *is not* symmetric with `TIMESTAMPADD` in all cases, as adding *1*
      `MONTH` to *Mar 31st* results in *Apr 30th*, but the `TIMESTAMPDIFF` in `MONTH`
      units between those two dates is *0*.
    </Info>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>TIMESTAMPDIFF(MONTH, DATETIME('2000-10-10 01:23:45.678'), DATETIME('2000-12-31 12:34:56.789'))</code></td>
            <td><code>2</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPDIFF(MONTH, DATETIME('2000-03-31 01:23:45.678'), DATETIME('2000-04-30 12:34:56.789'))</code></td>
            <td><code>0</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPDIFF(MONTH, DATETIME('2000-12-31 01:23:45.678'), DATETIME('2000-10-10 12:34:56.789'))</code></td>
            <td><code>-2</code></td>
          </tr>

          <tr>
            <td><code>TIMESTAMPDIFF(HOUR, DATETIME('2000-10-10 12:34:56.789'), TIMESTAMP(978222896678))</code></td>
            <td><code>1955</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="TIMESTAMP_TRUNC(part, expr)" id="timestamp_trunc-part-expr" defaultOpen>
    Alias for `DATE_TRUNC(part, expr)`
  </Accordion>

  <Accordion title="UNIX_TIMESTAMP(expr)" id="unix_timestamp-expr" defaultOpen>
    Alias for `SECS_SINCE_EPOCH(expr)`
  </Accordion>

  <Accordion title="WEEK(expr)" id="week-expr" defaultOpen>
    Extracts the week of the year from `expr` \[`1` - `54`]; each full week starts on
    *Sunday* (a `1` is returned for the week containing *Jan 1st*)
  </Accordion>

  <Accordion title="YEAR(expr)" id="year-expr" defaultOpen>
    Extracts the year from `expr`; 4-digit year, A.D.
  </Accordion>
</AccordionGroup>

<a id="sql-datetime-functions-complex" />

### Date/Time Complex Conversion Functions

<AccordionGroup>
  <Accordion title="DATE_TO_EPOCH_MSECS(year, month, day, hour, min, sec, msec)" id="date_to_epoch_msecs-year-month-day-hour-min-sec-msec" defaultOpen>
    Converts the full date to milliseconds since the epoch

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>DATE\_TO\_EPOCH\_MSECS(2017, 06, 15, 09, 22, 15, 42)</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>1497518535042</code></td>
          </tr>

          <tr>
            <td>**Resolves To**</td>
            <td>*Thursday, June 15, 2017 9:22:15.042 AM*</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="DATE_TO_EPOCH_SECS(year, month, day, hour, min, sec)" id="date_to_epoch_secs-year-month-day-hour-min-sec" defaultOpen>
    Converts the full date to seconds since the epoch

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>DATE\_TO\_EPOCH\_SECS(2017, 06, 15, 09, 22, 15)</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>1494926535</code></td>
          </tr>

          <tr>
            <td>**Resolves To**</td>
            <td>*Thursday, June 15, 2017 9:22:15.042 AM*</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="TIMESTAMP_FROM_DATE_TIME(date, time)" id="timestamp_from_date_time-date-time" defaultOpen>
    Converts the given date and time to a composite date/time format

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>TIMESTAMP\_FROM\_DATE\_TIME('2017-06-15', '10:37:30')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>2017-06-15 10:37:30.000</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="WEEK_TO_EPOCH_MSECS(year, week_number)" id="week_to_epoch_msecs-year-week_number" defaultOpen>
    Converts the year and week number to milliseconds since the epoch; negative
    values are accepted

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>WEEK\_TO\_EPOCH\_MSECS(2017,-32)</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>1463270400000</code></td>
          </tr>

          <tr>
            <td>**Resolves To**</td>
            <td>*Sunday, May 15, 2016 12:00:00 AM*</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="WEEK_TO_EPOCH_SECS(year, week_number)" id="week_to_epoch_secs-year-week_number" defaultOpen>
    Converts the year and week number to seconds since the epoch. Negative
    values are accepted.  Each new week begins Sunday at midnight.

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>WEEK\_TO\_EPOCH\_SECS(2017,-32)</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>1463270400</code></td>
          </tr>

          <tr>
            <td>**Resolves To**</td>
            <td>*Sunday, May 15, 2016 12:00:00 AM*</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>
</AccordionGroup>

<a id="sql-geo-functions" />

## Geospatial/Geometry Functions

Five types of geospatial functions are available in Kinetica:

* Scalar Functions - apply a geospatial function at the record level to WKT or
  X/Y data
* Enhanced Performance Scalar Functions - apply performance-optimized
  geospatial functions to X/Y data
* Aggregate Functions - apply a geospatial function across groups of records to
  WKT or X/Y data
* Track Functions - apply scalar & aggregate functions to
  [track-based data](/content/location_intelligence/geo_objects#geospatial-tracks)
* H3 Functions - apply H3 gridding functions to WKT or X/Y data

<Tip>
  - Use `ST_ISVALID` to determine if a geometry object is valid. The
    functions below work best with valid geometry objects.
  - Use the `REMOVE_NULLABLE` [function](/content/concepts/expressions#null-expression-functions) to
    remove any `nullable` column types that could result from calculating a
    derived column (e.g., as in [Projections](/content/concepts/projections)) using one of the
    functions below.
</Tip>

<a id="sql-geo-functions-scalar-ep" />

### Enhanced Performance Scalar Functions

The functions below all compare `x` and `y` coordinates to geometry objects
(or vice versa), thus increasing their performance in queries. Each of these
functions have a geometry-to-geometry version listed in the next section.

<AccordionGroup>
  <Accordion title="STXY_CONTAINS(geom, x, y)" id="stxy_contains-geom-x-y" defaultOpen>
    Returns `1` (true) if `geom` contains the `x` and `y` coordinate, e.g. lies in the interior
    of `geom`. The coordinate cannot be on the boundary and also be contained because `geom` does not
    contain its boundary
  </Accordion>

  <Accordion title="STXY_CONTAINSPROPERLY(geom, x, y)" id="stxy_containsproperly-geom-x-y" defaultOpen>
    Returns `1` (true) if the `x` and `y` coordinate intersects the interior of `geom` but not
    the boundary (or exterior) because `geom` does not contain its boundary but does contain itself
  </Accordion>

  <Accordion title="STXY_COVEREDBY(x, y, geom)" id="stxy_coveredby-x-y-geom" defaultOpen>
    Returns `1` (true) if the `x` and `y` coordinate is covered by `geom`
  </Accordion>

  <Accordion title="STXY_COVERS(geom, x, y)" id="stxy_covers-geom-x-y" defaultOpen>
    Returns `1` (true) if `geom` covers the `x` and `y` coordinate
  </Accordion>

  <Accordion title="STXY_DISJOINT(x, y, geom)" id="stxy_disjoint-x-y-geom" defaultOpen>
    Returns `1` (true) if the given `x` and `y` coordinate and the geometry `geom` do not
    spatially intersect.
  </Accordion>

  <Accordion title="STXY_DISTANCE (x, y, geom[, solution])" id="stxy_distance-x-y-geom-solution" defaultOpen>
    Calculates the minimum distance between the given `x` and `y` coordinate and `geom` using the
    specified solution type. Solution types available:

    * `0` (default) - Euclidean; returns 2-D Euclidean distance
    * `1` - Haversine; returns minimum sphere distance in meters
    * `2` - Vincenty; returns minimum spheroid distance in meters, more accurate than Haversine but
      slower performance

    <Info>
      If the `x` and `y` coordinate and `geom` intersect (verify using `ST_INTERSECTS`),
      the distance will always be `0`.
    </Info>
  </Accordion>

  <Accordion title="STXY_DWITHIN (x, y, geom, distance[, solution])" id="stxy_dwithin-x-y-geom-distance-solution" defaultOpen>
    Returns `1` (true) if the `x` and `y` coordinate is within the specified `distance` from
    `geom` using the specified solution type. Solution types available:

    * `0` (default) - Euclidean; uses degrees to calculate distance
    * `1` - Sphere; uses meters to calculate sphere distance
    * `2` - Spheroid; uses meters to calculate spheroid distance
  </Accordion>

  <Accordion title="STXY_ENVDWITHIN (x, y, geom, distance[, solution])" id="stxy_envdwithin-x-y-geom-distance-solution" defaultOpen>
    Returns `1` (true) if the `x` and `y` coordinate is within the specified `distance` from the
    bounding box of `geom` using the specified solution type. Solution types available:

    * `0` (default) - Euclidean; uses degrees to calculate distance
    * `1` - Sphere; uses meters to calculate distance
  </Accordion>

  <Accordion title="STXY_ENVINTERSECTS(x, y, geom)" id="stxy_envintersects-x-y-geom" defaultOpen>
    Returns `1` (true) if the bounding box of the given geometry `geom` intersects the `x` and
    `y` coordinate.
  </Accordion>

  <Accordion title="STXY_GEOHASH(x, y[, precision])" id="stxy_geohash-x-y-precision" defaultOpen>
    Returns a hash string representation of the given `x` and `y` coordinates with specified
    `precision` (the length of the resulting geohash string). The longer the `precision`, the more
    precise the hash is. By default, `precision` is set to `20`; the max for `precision` is `32`.

    See [Geohash](/content/snippets/geohash) for an example.
  </Accordion>

  <Accordion title="STXY_H3(x, y, resolution)" id="stxy_h3-x-y-resolution" defaultOpen>
    Alias for `H3_XYTOCELL`; see [H3 Functions](/content/location_intelligence/geo_functions#geo-functions-h3).
  </Accordion>

  <Accordion title="STXY_INTERSECTION(x, y, geom)" id="stxy_intersection-x-y-geom" defaultOpen>
    Returns the shared portion between the `x` and `y` coordinate and the given geometry `geom`,
    i.e. the point itself.
  </Accordion>

  <Accordion title="STXY_INTERSECTS(x, y, geom)" id="stxy_intersects-x-y-geom" defaultOpen>
    Returns `1` (true) if the `x` and `y` coordinate and `geom` intersect in 2-D.
  </Accordion>

  <Accordion title="STXY_TOUCHES(x, y, geom)" id="stxy_touches-x-y-geom" defaultOpen>
    Returns `1` (true) if the `x` and `y` coordinate and geometry `geom` have at least one point
    in common but their interiors do not intersect. If `geom` is a GEOMETRYCOLLECTION, a `0` is
    returned regardless if the point and geometry touch
  </Accordion>

  <Accordion title="STXY_WITHIN(x, y, geom)" id="stxy_within-x-y-geom" defaultOpen>
    Returns `1` (true) if the `x` and `y` coordinate is completely inside the `geom` geometry
    i.e., not on the boundary
  </Accordion>
</AccordionGroup>

<a id="sql-geo-functions-scalar" />

### Scalar Functions

<AccordionGroup>
  <Accordion title="DIST(x1, y1, x2, y2)" id="dist-x1-y1-x2-y2" defaultOpen>
    Computes the Euclidean distance (in degrees), i.e. `SQRT( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) )`.
  </Accordion>

  <Accordion title="GEODIST(lon1, lat1, lon2, lat2)" id="geodist-lon1-lat1-lon2-lat2" defaultOpen>
    Computes the geographic great-circle distance (in meters) between two lat/lon points.
  </Accordion>

  <Accordion title="GEOHASH_DECODE_LATITUDE(geohash)" id="geohash_decode_latitude-geohash" defaultOpen>
    Decodes a given `geohash` and returns the latitude value for the given hash string. Supports a
    maximum geohash character length of *16*.
  </Accordion>

  <Accordion title="GEOHASH_DECODE_LONGITUDE(geohash)" id="geohash_decode_longitude-geohash" defaultOpen>
    Decodes a given `geohash` and returns the longitude value for the given hash string. Supports a
    maximum geohash character length of *16*.
  </Accordion>

  <Accordion title="GEOHASH_ENCODE(lat, lon, precision)" id="geohash_encode-lat-lon-precision" defaultOpen>
    Encodes a given coordinate pair and returns a hash string with a given `precision`. The maximum `precision` is *15*.
  </Accordion>

  <Accordion title="GEOMETRY(wkt)" id="geometry-wkt" defaultOpen>
    Alias for `ST_GEOMFROMTEXT(wkt)`
  </Accordion>

  <Accordion title="ST_ADDPOINT (linestring, point[, position])" id="st_addpoint-linestring-point-position" defaultOpen>
    Adds a given `point` geometry to the given `linestring` geometry at the specified
    `position`, which is a 0-based index.  If no `position` is specified, the point will be added to the end.
  </Accordion>

  <Accordion title="ST_ALMOSTEQUALS (geom1, geom2[, decimal])" id="st_almostequals-geom1-geom2-decimal" defaultOpen>
    Returns `1` (true) if given geometries, `geom1` and `geom2`, are almost spatially equal within
    the given amount of `decimal` scale. Note that geometries will still be considered equal if the
    decimal scale for the geometries is within a half order of magnitude of each other; e.g., if
    `decimal` is set to 2, then `POINT(63.4 123.45)` and `POINT(63.4 123.454)` are equal, but
    `POINT(63.4 123.45)` and `POINT(63.4 123.459)` are *not* equal. The geometry types must match to be
    considered equal.

    If no `decimal` scale is specified, a default scale of *6* will be applied.
  </Accordion>

  <Accordion title="ST_AREA(geom[, solution])" id="st_area-geom-solution" defaultOpen>
    Returns the area of the given geometry `geom` if it is a POLYGON or MULTIPOLYGON using the
    specified solution type. Returns `0` if the input geometry type is (MULTI)POINT or
    (MULTI)LINESTRING. Solution types available:

    * `0` (default) - 2D Euclidean area
    * `1` - curved surface area on a sphere in square meters
    * `2` - curved surface area on a spheroid in square meters
  </Accordion>

  <Accordion title="ST_AZIMUTH(geom1, geom2)" id="st_azimuth-geom1-geom2" defaultOpen>
    Returns the azimuth in radians defined by the segment between two POINTs, `geom1` and `geom2`.
    Returns a `null` if the input geometry type is MULTIPOINT, (MULTI)LINESTRING, or (MULTI)POLYGON.
  </Accordion>

  <Accordion title="ST_BOUNDARY(geom)" id="st_boundary-geom" defaultOpen>
    Returns the closure of the combinatorial boundary of a given geometry `geom`. Returns an empty
    geometry if `geom` is an empty geometry. Returns a `null` if `geom` is a GEOMETRYCOLLECTION
  </Accordion>

  <Accordion title="ST_BOUNDINGDIAGONAL(geom)" id="st_boundingdiagonal-geom" defaultOpen>
    Returns the diagonal of the given geometry's (`geom`) bounding box.
  </Accordion>

  <Accordion title="ST_BUFFER (geom, radius[, style[, solution]])" id="st_buffer-geom-radius-style-solution" defaultOpen>
    Returns a geometry that represents all points whose distance from the given geometry `geom` is
    less than or equal to the given distance `radius`. The `radius` units can be specified by the
    `solution` type (default is in degrees) and the `radius` is created in the provided `style`.
    The `style` options are specified as a list of blank-separated key-value pairs, e.g.,
    `'quad_segs=8 endcap=round'`. If an empty `style` list (`''`) is provided, the default settings
    will be used. The `style` parameter must be specified to provide a `solution` type.

    Available `style` options:

    * `quad_segs` - the number of segments used to approximate a quarter circle (default is `8`)
    * `endcap` - the endcap style of the buffer (default is `round`); options are `round`,
      `flat` (or `butt`), and `square`
    * `join` - the join style of the buffer (default is `round`); options are `round`, `mitre`
      (or `miter`), and `bevel`
    * `mitre_limit` - the mitre ratio limit expressed as a floating-point number (`miter_limit` is
      also acceptable)

    Available `solution` types:

    * `0` (default) - 2D Euclidean radius distance in degrees
    * `1` - curved surface radius distance on a sphere in meters
    * `2` - curved surface radius distance on a spheroid in meters

    <Tip>
      To create a 5-meter buffer around `geom` using the default styles:
      `ST_BUFFER(geom, 5, '', 1)`. To create a 5-foot (converting feet to meters) buffer
      around `geom` using the following styles:
      `ST_BUFFER(geom, 5*0.3048,'quad_segs=4 endcap=flat', 1)`
    </Tip>
  </Accordion>

  <Accordion title="ST_BUFFERBYCOMPONENT (geom, radius[, style[, solution]])" id="st_bufferbycomponent-geom-radius-style-solution" defaultOpen>
    Returns a buffered geometry similar to the output of `ST_BUFFER` using the same parameters. The only
    difference is the buffered geometry is calculated by independently buffering each individual component
    and then the buffered components are dissolved (i.e. unioned) together to produce the final output. This
    can produce very similar (but not identical) results to `ST_BUFFER` but will often run much faster.
  </Accordion>

  <Accordion title="ST_CENTROID(geom)" id="st_centroid-geom" defaultOpen>
    Calculates the center of the given geometry `geom` as a POINT. For (MULTI)POINTs, the center is
    calculated as the average of the input coordinates. For (MULTI)LINESTRINGs, the center is calculated
    as the weighted length of each given LINESTRING. For (MULTI)POLYGONs, the center is calculated as
    the weighted area of each given POLYGON. If `geom` is an empty geometry, an empty
    GEOMETRYCOLLECTION is returned
  </Accordion>

  <Accordion title="ST_CLIP(geom1, geom2)" id="st_clip-geom1-geom2" defaultOpen>
    Returns the geometry shared between given geometries `geom1` and `geom2`
  </Accordion>

  <Accordion title="ST_CLOSESTPOINT (geom1, geom2[, solution])" id="st_closestpoint-geom1-geom2-solution" defaultOpen>
    Calculates the 2-D `POINT` in `geom1` that is closest to `geom2` using the specified solution
    type. If `geom1` or `geom2` is empty, a `null` is returned. Solution types available:

    * `0` (default) - Euclidean; calculates the closest point using 2-D Euclidean distance
    * `1` - Haversine; calculates the closest point using sphere distance in meters
    * `2` - Vincenty; returns minimum spheroid distance in meters, more accurate than Haversine but
      slower performance
  </Accordion>

  <Accordion title="ST_COLLECT(geom1, geom2)" id="st_collect-geom1-geom2" defaultOpen>
    Returns a MULTI\* or GEOMETRYCOLLECTION comprising `geom1` and `geom2`. If `geom1` and `geom2`
    are the same, singular geometry type, a MULTI\* is returned, e.g., if `geom1` and `geom2` are both
    POINTs (empty or no), a MULTIPOINT is returned. If `geom1` and `geom2` are neither the same type
    nor singular geometries, a GEOMETRYCOLLECTION is returned.
  </Accordion>

  <Accordion title="ST_COLLECTIONEXTRACT (collection, type)" id="st_collectionextract-collection-type" defaultOpen>
    Returns only the specified `type` from the given geometry `collection`. Type is a number that
    maps to the following:

    * `1` = `POINT`
    * `2` = `LINESTRING`
    * `3` = `POLYGON`
  </Accordion>

  <Accordion title="ST_COLLECTIONHOMOGENIZE(collection)" id="st_collectionhomogenize-collection" defaultOpen>
    Returns the simplest form of the given `collection`, e.g., a collection with a single POINT will
    be returned as `POINT(x y)`, and a collection with multiple individual points will be returned as a
    MULTIPOINT.
  </Accordion>

  <Accordion title="ST_CONCAVEHULL (geom, target_percent[, allow_holes])" id="st_concavehull-geom-target_percent-allow_holes" defaultOpen>
    Returns a potentially concave geometry that encloses all geometries found in the given `geom` set.
    Use `target_percent` (values between 0 and 1) to determine the percent of area of a convex hull the
    concave hull will attempt to fill; `1` will return the same geometry as an `ST_CONVEXHULL`
    operation. Set `allow_holes` to `1` (true) to allow holes in the resulting geometry; default
    value is `0` (false). Note that `allow_holes` is independent of the area of `target_percent`.
  </Accordion>

  <Accordion title="ST_CONTAINS(geom1, geom2)" id="st_contains-geom1-geom2" defaultOpen>
    Returns `1` (true) if no points of `geom2` lie in the exterior of `geom1` and at least one
    point of `geom2` lies in the interior of `geom1`. Note that `geom1` does not contain its
    boundary but does contain itself.
  </Accordion>

  <Accordion title="ST_CONTAINSPROPERLY(geom1, geom2)" id="st_containsproperly-geom1-geom2" defaultOpen>
    Returns `1` (true) if `geom2` intersects the interior of `geom1` but not the boundary
    (or exterior). Note that `geom1` does not contain its boundary but does contain itself.
  </Accordion>

  <Accordion title="ST_CONVEXHULL(geom)" id="st_convexhull-geom" defaultOpen>
    Returns the minimum convex geometry that encloses all geometries in the given `geom` set.
  </Accordion>

  <Accordion title="ST_COORDDIM(geom)" id="st_coorddim-geom" defaultOpen>
    Returns the coordinate dimension of the given `geom`, e.g., a geometry with `x`, `y`, and `z`
    coordinates would return `3`.
  </Accordion>

  <Accordion title="ST_COVEREDBY(geom1, geom2)" id="st_coveredby-geom1-geom2" defaultOpen>
    Returns `1` (true) if no point in `geom1` is outside `geom2`.
  </Accordion>

  <Accordion title="ST_COVERS(geom1, geom2)" id="st_covers-geom1-geom2" defaultOpen>
    Returns `1` (true) if no point in `geom2` is outside `geom1`.
  </Accordion>

  <Accordion title="ST_CROSSES(geom1, geom2)" id="st_crosses-geom1-geom2" defaultOpen>
    Returns `1` (true) if the given geometries, `geom1` and `geom2`, spatially cross, meaning some
    but not all interior points in common. If `geom1` and/or `geom2` are a GEOMETRYCOLLECTION, a
    `0` is returned regardless of if the two geometries cross
  </Accordion>

  <Accordion title="ST_DIFFERENCE(geom1, geom2)" id="st_difference-geom1-geom2" defaultOpen>
    Returns a geometry that represents the part of `geom1` that does not intersect with `geom2`.
  </Accordion>

  <Accordion title="ST_DIMENSION(geom)" id="st_dimension-geom" defaultOpen>
    Returns the dimension of the given geometry `geom`, which is less than or equal to the coordinate
    dimension. If `geom` is a single geometry, a `0` is for `POINT`, a `1` is for `LINESTRING`,
    and a `2` is for `POLYGON`. If `geom` is a collection, it will return the largest dimension from
    the collection. If `geom` is empty, `0` is returned.
  </Accordion>

  <Accordion title="ST_DISJOINT(geom1, geom2)" id="st_disjoint-geom1-geom2" defaultOpen>
    Returns `1` (true) if the given geometries, `geom1` and `geom2`, do not spatially intersect.
  </Accordion>

  <Accordion title="ST_DISTANCE(geom1, geom2[, solution])" id="st_distance-geom1-geom2-solution" defaultOpen>
    Calculates the minimum distance between the given geometries, `geom1` and `geom2`, using the
    specified solution type. Solution types available:

    * `0` (default) - Euclidean; returns 2-D Euclidean distance
    * `1` - Haversine; returns minimum sphere distance in meters
    * `2` - Vincenty; returns minimum spheroid distance in meters, more accurate than Haversine but
      slower performance

    <Info>
      If `geom1` and `geom2` intersect (verify using `ST_INTERSECTS`), the distance will
      always be `0`.
    </Info>
  </Accordion>

  <Accordion title="ST_DISTANCEPOINTS (x1, y1, x2, y2[, solution])" id="st_distancepoints-x1-y1-x2-y2-solution" defaultOpen>
    Calculates the minimum distance between the given points, `x1, y1` and `x2, y2`, using the
    specified solution type. Solution types available:

    * `0` (default) - Euclidean; returns 2-D Euclidean distance
    * `1` - Haversine; returns minimum sphere distance in meters
    * `2` - Vincenty; returns minimum spheroid distance in meters, more accurate than Haversine but
      slower performance
  </Accordion>

  <Accordion title="ST_DFULLYWITHIN (geom1, geom2, distance[, solution])" id="st_dfullywithin-geom1-geom2-distance-solution" defaultOpen>
    Returns `1` (true) if the maximum distance between geometries `geom1` and `geom2` is less than
    or equal to the specified `distance` of each other using the specified solution type. If `geom1`
    or `geom2` is `null`, `0` (false) is returned. Solution types available:

    * `0` (default) - Euclidean; uses degrees to calculate distance
    * `1` - Sphere; uses meters to calculate distance
    * `2` - Spheroid; uses meters to calculate distance, more accurate than sphere but slower
      performance
  </Accordion>

  <Accordion title="ST_DWITHIN (geom1, geom2, distance[, solution])" id="st_dwithin-geom1-geom2-distance-solution" defaultOpen>
    Returns `1` (true) if the minimum distance between geometries `geom1` and `geom2` is within the
    specified `distance` of each other using the specified solution type. Solution types available:

    * `0` (default) - Euclidean; uses degrees to calculate distance
    * `1` - Sphere; uses meters to calculate distance
    * `2` - Spheroid; uses meters to calculate distance, more accurate than sphere but slower
      performance
  </Accordion>

  <Accordion title="ST_ELLIPSE(x, y, height, width)" id="st_ellipse-x-y-height-width" defaultOpen>
    Returns an ellipse using the following values:

    * `x` - the x coordinate or longitude used to center the ellipse
    * `y` - the y coordinate or latitude used to center the ellipse
    * `height` - the height of the ellipse (in degrees)
    * `width` - the width of the ellipse (in degrees)
  </Accordion>

  <Accordion title="ST_ENDPOINT(geom)" id="st_endpoint-geom" defaultOpen>
    Returns the last point of the given `geom` as a POINT if it's a LINESTRING.  If `geom` is not
    a LINESTRING, `null` is returned.
  </Accordion>

  <Accordion title="ST_ENVDWITHIN (geom1, geom2, distance[, solution])" id="st_envdwithin-geom1-geom2-distance-solution" defaultOpen>
    Returns `1` (true) if `geom1` is within the specified `distance` of the bounding box of
    `geom2` using the specified solution type. Solution types available:

    * `0` (default) - Euclidean; uses degrees to calculate distance
    * `1` - Sphere; uses meters to calculate distance
  </Accordion>

  <Accordion title="ST_ENVELOPE(geom)" id="st_envelope-geom" defaultOpen>
    Returns the bounding box of a given geometry `geom`.
  </Accordion>

  <Accordion title="ST_ENVINTERSECTS(geom1, geom2)" id="st_envintersects-geom1-geom2" defaultOpen>
    Returns `1` (true) if the bounding box of the given geometries, `geom1` and `geom2`, intersect.
  </Accordion>

  <Accordion title="ST_EQUALS(geom1, geom2)" id="st_equals-geom1-geom2" defaultOpen>
    Returns `1` (true) if the given geometries, `geom1` and `geom2`, are spatially equal. Note that
    order does not matter.
  </Accordion>

  <Accordion title="ST_EQUALSEXACT (geom1, geom2[, tolerance])" id="st_equalsexact-geom1-geom2-tolerance" defaultOpen>
    Returns `1` (true) if the given geometries, `geom1` and `geom2`, are almost spatially equal
    within some given `tolerance`. If the values within the given geometries are within the
    `tolerance` value of each other, they're considered equal, e.g., if `tolerance` is 2,
    POINT(1 1) and POINT(1 3) are considered equal, but POINT(1 1) and POINT(1 3.1) are not. Note that
    the geometry types have to match for them to be considered equal.  The default `tolerance` is *0*,
    which makes this function effectively equivalent to `ST_EQUALS(geom1, geom2)` in the default case.
  </Accordion>

  <Accordion title="ST_ERASE(geom1, geom2)" id="st_erase-geom1-geom2" defaultOpen>
    Returns the result of erasing a portion of `geom1` equal to the size of `geom2`.
  </Accordion>

  <Accordion title="ST_EXPAND(geom, units)" id="st_expand-geom-units" defaultOpen>
    Returns the bounding box expanded in all directions by the given `units` of the given `geom`. The
    expansion can also be defined for separate directions by providing separate parameters for each
    direction, e.g., `ST_EXPAND(geom, unitsx, unitsy, unitsz, unitsm)`.
  </Accordion>

  <Accordion title="ST_EXPANDBYRATE(geom, rate)" id="st_expandbyrate-geom-rate" defaultOpen>
    Returns the bounding box expanded by a given `rate` (a ratio of width and height) for the given
    geometry `geom`. The `rate` must be between 0 and 1.
  </Accordion>

  <Accordion title="ST_EXTERIORRING(geom)" id="st_exteriorring-geom" defaultOpen>
    Returns a LINESTRING representing the exterior ring of the given POLYGON `geom`
  </Accordion>

  <Accordion title="ST_FORCE2D(geom)" id="st_force2d-geom" defaultOpen>
    Returns the 2-dimensional version (e.g., X and Y coordinates) of `geom`, the provided geometry or
    set of geometries (e.g., via GEOMETRYCOLLECTION or WKT column name).
  </Accordion>

  <Accordion title="ST_FORCE3D(geom[, z])" id="st_force3d-geom-z" defaultOpen>
    Returns the 3-dimensional version (e.g., X, Y, and Z coordinates) of `geom`, a provided geometry or
    set of geometries (e.g., via GEOMETRYCOLLECTION or WKT column name), using `z` as the geometry's
    new z-value. The provided z-values can also be derived from a numeric column. If no `z` is provided,
    a `0` will be applied.

    <Info>
      If a WKT column is provided for `geom` and a numeric column is provided for `z`, the z
      values will be matched to the provided geometries by row in the source table. If a singular
      geometry is provided for `geom` and a column is provided for `z`, three-dimensional
      versions of the provided geometry will be returned for each z value found in the provided
      `z` column. If columns are provided for both `geom` and `z` and nulls are present in
      either column, the row containing null values will be skipped in the results.
    </Info>
  </Accordion>

  <Accordion title="ST_GENERATEPOINTS(geom, num)" id="st_generatepoints-geom-num" defaultOpen>
    Creates a MULTIPOINT containing a number `num` of randomly generated points within the boundary of
    `geom`.
  </Accordion>

  <Accordion title="ST_GEOHASH(geom[, precision])" id="st_geohash-geom-precision" defaultOpen>
    Returns a hash string representation of the given geometry `geom` with specified `precision`
    (the length of the resulting geohash string). The longer the `precision`, the more precise the hash is. By
    default, `precision` is set to `20`; the max for `precision` is `32`. Returns `null` if
    `geom` is an empty geometry.

    See [Geohash](/content/snippets/geohash) for an example.

    <Info>
      The value returned will *not* be a geohash of the exact geometry but a geohash of the
      centroid of the given geometry
    </Info>
  </Accordion>

  <Accordion title="ST_GEOMETRYFROMTEXT(wkt)" id="st_geometryfromtext-wkt" defaultOpen>
    Alias for `ST_GEOMFROMTEXT(wkt)`
  </Accordion>

  <Accordion title="ST_GEOMETRYN(geom, index)" id="st_geometryn-geom-index" defaultOpen>
    Returns the `index` geometry back from the given `geom` geometry. The `index` starts from 1 and goes to
    the number of geometries in `geom`.
  </Accordion>

  <Accordion title="ST_GEOMETRYTYPE(geom)" id="st_geometrytype-geom" defaultOpen>
    Returns the type of geometry from the given `geom`.
  </Accordion>

  <Accordion title="ST_GEOMETRYTYPEID(geom)" id="st_geometrytypeid-geom" defaultOpen>
    Returns the type ID of from `geom`. Type and ID mappings:

    * POINT = 0
    * LINESTRING = 1
    * POLYGON = 3
    * MULTIPOINT = 4
    * MULTILINESTRING = 5
    * MULTIPOLYGON = 6
    * GEOMETRYCOLLECTION = 7
  </Accordion>

  <Accordion title="ST_GEOMFROMGEOHASH (geohash[, precision])" id="st_geomfromgeohash-geohash-precision" defaultOpen>
    Returns a POLYGON boundary box using the given `geohash` with a precision set by the integer
    `precision`. If `precision` is specified, the function will use as many characters in the hash
    equal to `precision` to create the geometry. If no `precision` is specified, the full length of
    the `geohash` is used.

    See [Geohash](/content/snippets/geohash) for an example.
  </Accordion>

  <Accordion title="ST_GEOMFROMH3(h3_index)" id="st_geomfromh3-h3_index" defaultOpen>
    Alias for `H3_CELLTOBOUNDARY`; see [H3 Functions](/content/location_intelligence/geo_functions#geo-functions-h3).
  </Accordion>

  <Accordion title="ST_GEOMFROMTEXT(wkt)" id="st_geomfromtext-wkt" defaultOpen>
    Returns a geometry from the given Well-Known text representation `wkt`. Note that this function is
    only compatible with constants.
  </Accordion>

  <Accordion title="ST_H3(wkt, resolution)" id="st_h3-wkt-resolution" defaultOpen>
    Alias for `H3_GEOMTOCELL`; see [H3 Functions](/content/location_intelligence/geo_functions#geo-functions-h3).
  </Accordion>

  <Accordion title="ST_HEXGRID (xmin, ymin, xmax, ymax, cell_side[, limit])" id="st_hexgrid-xmin-ymin-xmax-ymax-cell_side-limit" defaultOpen>
    Creates a MULTIPOLYGON containing a grid of hexagons between given minimum and maximum points of a
    bounding box. The minimum point cannot be greater than or equal to the maximum point. The size (in
    meters) of the individual hexagons' sides is determined by `cell_side`. The `cell_side` cannot be
    greater than the width or height of the bounding box. The maximum number of cells that can be
    produced is determined by `limit`, a positive integer. Supported values for `limit`:

    * `-1` - No limit to the number of cells generated (effectively limited by system memory)
    * `0` (default) - 100 million cells
    * `<n>` - Custom limit of `n` cells

    If the custom limit request specifies more cells (based on the bounding box and the `cell_side`)
    than the system limit, a `null` is returned.
  </Accordion>

  <Accordion title="ST_INTERIORRINGN(geom, n)" id="st_interiorringn-geom-n" defaultOpen>
    Returns the `n`-th interior LINESTRING ring of the POLYGON `geom`. If `geom` is not a POLYGON
    or the given `n` is out of range, a `null` is returned. The index begins at 1
  </Accordion>

  <Accordion title="ST_INTERSECTION(geom1, geom2)" id="st_intersection-geom1-geom2" defaultOpen>
    Returns the shared portion between given geometries `geom1` and `geom2`
  </Accordion>

  <Accordion title="ST_INTERSECTS(geom1, geom2)" id="st_intersects-geom1-geom2" defaultOpen>
    Returns `1` (true) if the given geometries, `geom1` and `geom2`, intersect in 2-D
  </Accordion>

  <Accordion title="ST_ISCLOSED(geom)" id="st_isclosed-geom" defaultOpen>
    Returns `1` (true) if the given geometry's (`geom`) start and end points coincide
  </Accordion>

  <Accordion title="ST_ISCOLLECTION(geom)" id="st_iscollection-geom" defaultOpen>
    Returns `1` (true) if `geom` is a collection, e.g., GEOMETRYCOLLECTION, MULTIPOINT,
    MULTILINESTRING, etc.
  </Accordion>

  <Accordion title="ST_ISEMPTY(geom)" id="st_isempty-geom" defaultOpen>
    Returns `1` (true) if `geom` is empty
  </Accordion>

  <Accordion title="ST_ISRING(geom)" id="st_isring-geom" defaultOpen>
    Returns `1` (true) if LINESTRING `geom` is both closed (per `ST_ISCLOSED`) and "simple"
    (per `ST_ISSIMPLE`). Returns `0` if `geom` is not a LINESTRING
  </Accordion>

  <Accordion title="ST_ISSIMPLE(geom)" id="st_issimple-geom" defaultOpen>
    Returns `1` (true) if `geom` has no anomalous geometric points, e.g., self-intersection or
    self-tangency
  </Accordion>

  <Accordion title="ST_ISVALID(geom)" id="st_isvalid-geom" defaultOpen>
    Returns `1` (true) if `geom` (typically a \[MULTI]POLYGON) is well formed. A POLYGON is valid if
    its rings do not cross, and its boundary intersects only at POINTs (not along a line). The POLYGON must
    also not have dangling LINESTRINGs. A MULTIPOLYGON is valid if all of its elements are also valid, and
    the interior rings of those elements do not intersect. Each element's boundaries may touch but only
    at POINTs (not along a line).  `ST_MAKEVALID(geom)` can be used to help correct invalid geometries.
  </Accordion>

  <Accordion title="ST_ISVALIDREASON(geom)" id="st_isvalidreason-geom" defaultOpen>
    Returns `Valid Geometry` if `geom` is well formed, according to `ST_ISVALID(geom)`; otherwise,
    returns the reason `geom` is determined to be malformed.  `ST_MAKEVALID(geom)` can be used to
    help correct invalid geometries.

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>ST\_ISVALIDREASON('POLYGON((-1 0, 1 0, 1 1, -1 -1))')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>Self-intersection\[0 0]</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="ST_LENGTH(geom[, solution])" id="st_length-geom-solution" defaultOpen>
    Returns the length of the geometry if it is a LINESTRING or MULTILINESTRING. Returns `0` if
    another type of geometry, e.g., POINT, MULTIPOINT, etc. GEOMETRYCOLLECTIONs are
    also supported but the aforementioned type limitation still applies; the collection will be
    recursively searched for LINESTRINGs and MULTILINESTRINGs and the summation of all supported geometry
    types is returned (unsupported types are ignored). Solution types available:

    * `0` (default) - 2D Euclidean length
    * `1` - length on a sphere in meters
    * `2` - length on a spheroid in meters
  </Accordion>

  <Accordion title="ST_LINEFROMMULTIPOINT(geom)" id="st_linefrommultipoint-geom" defaultOpen>
    Creates a LINESTRING from `geom` if it is a MULTIPOINT. Returns `null` if `geom` is not a
    MULTIPOINT
  </Accordion>

  <Accordion title="ST_LINEINTERPOLATEPOINT(geom, frac)" id="st_lineinterpolatepoint-geom-frac" defaultOpen>
    Returns a POINT on the LINESTRING `geom` that is the `frac` fraction of the distance along the line. If `geom` is either
    empty or **not** a LINESTRING, `null` is returned
  </Accordion>

  <Accordion title="ST_LINELOCATEPOINT(linestring, point)" id="st_linelocatepoint-linestring-point" defaultOpen>
    Returns the location of the closest point in the given `linestring` to the given `point` as a
    value between `0` and `1`. The return value is a fraction of the total `linestring` length.
  </Accordion>

  <Accordion title="ST_LINEMERGE(geom)" id="st_linemerge-geom" defaultOpen>
    Returns a LINESTRING or MULTILINESTRING from a given `geom`. If `geom` is a MULTILINESTRING
    comprising LINESTRINGs with shared endpoints, a contiguous LINESTRING is returned. If `geom` is a
    LINESTRING or a MULTILINESTRING comprising LINESTRINGS without shared endpoints, `geom` is returned
    If `geom` is an empty (MULTI)LINESTRING or a (MULTI)POINT or (MULTI)POLYGON, an empty
    GEOMETRYCOLLECTION is returned.
  </Accordion>

  <Accordion title="ST_LINESUBSTRING (geom, start_frac, end_frac)" id="st_linesubstring-geom-start_frac-end_frac" defaultOpen>
    Returns the fraction of a given `geom` LINESTRING from the point that is the `start_frac` fraction of the distance along
    the line to the point that is the `end_frac` fraction of the distance along the line.

    For example, given `LINESTRING(1 1, 2 2, 3 3)` a `start_fraction` of `0` and an `end_fraction` of `0.25` would yield
    the first quarter of the given LINESTRING, or `LINESTRING(1 1, 1.5 1.5)`.

    Returns `null` in the following cases:

    * input geometry is (MULTI)POINT, MULTILINESTRING, or (MULTI)POLYGON
    * `start_frac` is greater than `end_frac`
    * `start_frac` or `end_frac` are not between `0` & `1`, inclusive
  </Accordion>

  <Accordion title="ST_LONGESTLINE (geom1, geom2[, solution])" id="st_longestline-geom1-geom2-solution" defaultOpen>
    Returns the LINESTRING that represents the longest line of points between the two geometries. If
    multiple longest lines are found, only the first line found is returned. If `geom1` or `geom2` is
    empty, `null` is returned. Solution types available:

    * `0` (default) - Euclidean; uses degrees to calculate the longest line
    * `1` - Sphere; uses meters to calculate the longest line
    * `2` - Spheroid; uses meters to calculate the longest line, more accurate than sphere but slower
      performance
  </Accordion>

  <Accordion title="ST_MAKEENVELOPE (xmin, ymin, xmax, ymax)" id="st_makeenvelope-xmin-ymin-xmax-ymax" defaultOpen>
    Creates a rectangular POLYGON from the given min and max parameters
  </Accordion>

  <Accordion title="ST_MAKELINE(geom[, geom2])" id="st_makeline-geom-geom2" defaultOpen>
    Creates a LINESTRING from `geom` if it is a MULTIPOINT. If `geom` is a POINT, there must be at
    least one other POINT to construct a LINESTRING. If `geom` is a LINESTRING, it must have at least
    two points. Returns `null` if `geom` is not a POINT, MULTIPOINT, or LINESTRING

    <Info>
      This function can be rather costly in terms of performance
    </Info>
  </Accordion>

  <Accordion title="ST_MAKEPOINT(x, y)" id="st_makepoint-x-y" defaultOpen>
    Creates a POINT at the given coordinate

    <Info>
      This function can be rather costly in terms of performance
    </Info>
  </Accordion>

  <Accordion title="ST_MAKEPOLYGON(geom)" id="st_makepolygon-geom" defaultOpen>
    Creates a POLYGON from `geom`. Inputs must be closed LINESTRINGs

    <Info>
      This function can be rather costly in terms of performance
    </Info>
  </Accordion>

  <Accordion title="ST_MAKETRIANGLE2D (x1, y1, x2, y2, x3, y3)" id="st_maketriangle2d-x1-y1-x2-y2-x3-y3" defaultOpen>
    Creates a closed 2-D POLYGON with three vertices
  </Accordion>

  <Accordion title="ST_MAKETRIANGLE3D (x1, y1, z1, x2, y2, z2, x3, y3, z3)" id="st_maketriangle3d-x1-y1-z1-x2-y2-z2-x3-y3-z3" defaultOpen>
    Creates a closed 3-D POLYGON with three vertices
  </Accordion>

  <Accordion title="ST_MAKEVALID(geom[, options])" id="st_makevalid-geom-options" defaultOpen>
    Attempts to convert `geom` into a valid geometry when it is malformed, as determined by
    `ST_ISVALID(geom)`.  Returns `geom` if it is a valid geometry already.  The method used to convert
    invalid geometries into valid ones can be specified in `options` as a space-separated string of
    `x=y` key/value pairs.  The keys and corresponding values are as follows:

    * `method` - the algorithm used to convert invalid geometries into valid ones; either:

      * `linework` (default) - build geometry from lines extracted from `geom`
      * `structure` - build geometry from interior & exterior rings extracted from `geom`

    * `keepcollapsed` - if using the `method` of `structure`, whether to drop portions of the
      converted geometry that collapse to lower dimensions:

      * `true` (default) - keep portions of geometry that collapse to lower dimensions
      * `false` - don't keep portions of geometry that collapse to lower dimensions

    Example using default *linework* method:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>ST\_MAKEVALID('POLYGON((-1 0, 1 0, 1 1, -1 -1))')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>MULTIPOLYGON (((-1 -1, -1 0, 0 0, -1 -1)), ((1 0, 0 0, 1 1, 1 0)))</code></td>
          </tr>
        </tbody>
      </table>
    </div>

    Example using the *structure* method without dropping collapsible parts of the converted geometry:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>ST\_MAKEVALID('POLYGON((0 0, 0 0, 0 0, 0 0))', 'method=structure keepcollapsed=true')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>POINT (0 0)</code></td>
          </tr>
        </tbody>
      </table>
    </div>

    Example using the *structure* method with dropping collapsible parts of the converted geometry:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>ST\_MAKEVALID('POLYGON((0 0, 0 0, 0 0, 0 0))', 'method=structure keepcollapsed=false')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>POLYGON EMPTY</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="ST_MAXDISTANCE (geom1, geom2[, solution])" id="st_maxdistance-geom1-geom2-solution" defaultOpen>
    Returns the maximum distance between the given `geom1` and `geom2` geometries using the specified
    solution type. If `geom1` or `geom2` is empty, `null` is returned. Solution types available:

    * `0` (default) - returns maximum 2-D Euclidean distance
    * `1` - Sphere; returns maximum distance in meters
    * `2` - Spheroid; returns maximum distance in meters, more accurate than sphere but slower
      performance
  </Accordion>

  <Accordion title="ST_MAXX(geom)" id="st_maxx-geom" defaultOpen>
    Returns the maximum x coordinate of a bounding box for the given `geom` geometry. This function
    works for 2-D and 3-D geometries.
  </Accordion>

  <Accordion title="ST_MAXY(geom)" id="st_maxy-geom" defaultOpen>
    Returns the maximum y coordinate of a bounding box for the given `geom` geometry. This function
    works for 2-D and 3-D geometries.
  </Accordion>

  <Accordion title="ST_MAXZ(geom)" id="st_maxz-geom" defaultOpen>
    Returns the maximum z coordinate of a bounding box for the given `geom` geometry. This function
    works for 2-D and 3-D geometries.
  </Accordion>

  <Accordion title="ST_MINX(geom)" id="st_minx-geom" defaultOpen>
    Returns the minimum x coordinate of a bounding box for the given `geom` geometry. This function
    works for 2-D and 3-D geometries.
  </Accordion>

  <Accordion title="ST_MINY(geom)" id="st_miny-geom" defaultOpen>
    Returns the minimum y coordinate of a bounding box for the given `geom` geometry. This function
    works for 2-D and 3-D geometries.
  </Accordion>

  <Accordion title="ST_MINZ(geom)" id="st_minz-geom" defaultOpen>
    Returns the minimum z coordinate of a bounding box for the given `geom` geometry. This function
    works for 2-D and 3-D geometries.
  </Accordion>

  <Accordion title="ST_MULTI(geom)" id="st_multi-geom" defaultOpen>
    Returns `geom` as a MULTI- geometry, e.g., a POINT would return a MULTIPOINT.
  </Accordion>

  <Accordion title="ST_MULTIPLERINGBUFFERS (geom, distance[, outside])" id="st_multipleringbuffers-geom-distance-outside" defaultOpen>
    Creates multiple buffers at specified `distance` around the given `geom` geometry. Multiple
    distances are specified as comma-separated values in an array, e.g., `[10,20,30]`. Valid values for
    `outside` are:

    * `FULL` - indicates that buffers will overlap or cover the given `geom` geometry. This is the
      default.
    * `OUTSIDE_ONLY` - indicates that buffers will be rings around the given `geom` geometry.
  </Accordion>

  <Accordion title="ST_NDIMS(geom)" id="st_ndims-geom" defaultOpen>
    Returns the number of dimensions in `geom`.  For X,Y data, this will return 2; if a Z component is
    present, it will return 3.
  </Accordion>

  <Accordion title="ST_NEAR(geom1, geom2)" id="st_near-geom1-geom2" defaultOpen>
    Returns the portion of `geom2` that is closest to `geom1`. If `geom2` is a singular geometry
    object (e.g., POINT, LINESTRING, POLYGON), `geom2` will be returned. If `geom2` a multi-geometry,
    e.g., MULTIPOINT, MULTILINESTRING, etc., the nearest singular geometry in `geom2` will be
    returned.
  </Accordion>

  <Accordion title="ST_NORMALIZE(geom)" id="st_normalize-geom" defaultOpen>
    Returns `geom` in its normalized (canonical) form, which may rearrange the points in lexicographical
    order.
  </Accordion>

  <Accordion title="ST_NPOINTS(geom)" id="st_npoints-geom" defaultOpen>
    Returns the number of points (vertices) in `geom`.
  </Accordion>

  <Accordion title="ST_NRINGS(geom)" id="st_nrings-geom" defaultOpen>
    Returns the total number of rings (including interior rings) in `geom`.  For non-polygonal geometries,
    it will return 0. For MULTIPOLYGONs, it will return the total number of rings across all components.
  </Accordion>

  <Accordion title="ST_NUMGEOMETRIES(geom)" id="st_numgeometries-geom" defaultOpen>
    If `geom` is a collection or MULTI- geometry, returns the number of geometries. If `geom` is a
    single geometry, returns 1.
  </Accordion>

  <Accordion title="ST_NUMINTERIORRINGS(geom)" id="st_numinteriorrings-geom" defaultOpen>
    Returns the number of interior rings if `geom` is a POLYGON. Returns `null` if `geom` is
    anything else.
  </Accordion>

  <Accordion title="ST_NUMPOINTS(geom)" id="st_numpoints-geom" defaultOpen>
    Returns the number of points in the `geom` LINESTRING. Returns `null` if `geom` is not a
    LINESTRING.
  </Accordion>

  <Accordion title="ST_OVERLAPS(geom1, geom2)" id="st_overlaps-geom1-geom2" defaultOpen>
    Returns `1` (true) if given geometries `geom1` and `geom2` share space. If `geom1` and/or
    `geom2` are a GEOMETRYCOLLECTION, a `0` is returned regardless of if the two geometries overlap
  </Accordion>

  <Accordion title="ST_PARTITION(geom[, threshold])" id="st_partition-geom-threshold" defaultOpen>
    Returns a MULTIPOLYGON representing the given `geom` partitioned into a number of POLYGONs with a
    maximum number of vertices equal to the given `threshold`. Minimum value for `threshold` is
    `10`; default value is `10000`. If `geom` is not a POLYGON or MULTIPOLYGON, `geom` is
    returned. If the number of vertices in `geom` is less than the `threshold`, `geom` is returned.
  </Accordion>

  <Accordion title="ST_PERIMETER(geom[, solution])" id="st_perimeter-geom-solution" defaultOpen>
    Returns the perimeter of the geometry if it is a POLYGON or MULTIPOLYGON. Returns `0` if another
    type of geometry, e.g., POINT, MULTIPOINT, LINESTRING, or MULTILINESTRING. GEOMETRYCOLLECTIONs are
    also supported but the aforementioned type limitation still applies; the collection will be
    recursively searched for POLYGONs and MULTIPOLYGONs and the summation of all supported geometry types
    is returned (unsupported types are ignored). Solution types available:

    * `0` (default) - 2D Euclidean length
    * `1` - length on a sphere in meters
    * `2` - length on a spheroid in meters
  </Accordion>

  <Accordion title="ST_POINT(x, y)" id="st_point-x-y" defaultOpen>
    Returns a POINT with the given `x` and `y` coordinates.
  </Accordion>

  <Accordion title="ST_POINTFROMGEOHASH (geohash[, precision])" id="st_pointfromgeohash-geohash-precision" defaultOpen>
    Returns a POINT using the given `geohash` with a precision set by the integer `precision`. If
    `precision` is specified, the function will use as many characters in the hash equal to
    `precision` to create the geometry. If no `precision` is specified, the full length of
    the `geohash` is used.

    <Info>
      The POINT returned represents the center of the bounding box of the geohash
    </Info>
  </Accordion>

  <Accordion title="ST_POINTGRID (xmin, ymin, xmax, ymax, cell_side[, limit])" id="st_pointgrid-xmin-ymin-xmax-ymax-cell_side-limit" defaultOpen>
    Creates a MULTIPOLYGON containing a square-shaped grid of points between given minimum and maximum
    points of a bounding box. The minimum point cannot be greater than or equal to the maximum point. The
    distance between the points (in meters) is determined by `cell_side`. The `cell_side` cannot be
    greater than the width or height of the bounding box. The maximum number of cells that can be
    produced is determined by `limit`, a positive integer. Supported values for `limit`:

    * `-1` - No limit to the number of cells generated (effectively limited by system memory)
    * `0` (default) - 100 million cells
    * `<n>` - Custom limit of `n` cells

    If the custom limit request specifies more cells (based on the bounding box and the `cell_side`)
    than the system limit, a `null` is returned.
  </Accordion>

  <Accordion title="ST_POINTN(geom, n)" id="st_pointn-geom-n" defaultOpen>
    Returns the `n`-th point in LINESTRING `geom`. Negative values are valid, but note that they are
    counted backwards from the end of `geom`. A `null` is returned if `geom` is not a LINESTRING.
  </Accordion>

  <Accordion title="ST_POINTS(geom)" id="st_points-geom" defaultOpen>
    Returns a MULTIPOINT containing all of the coordinates of `geom`.
  </Accordion>

  <Accordion title="ST_PROJECT(geom, distance, azimuth)" id="st_project-geom-distance-azimuth" defaultOpen>
    Returns a POINT projected from a start point `geom` along a geodesic calculated using `distance`
    and `azimuth`. If `geom` is **not** a POINT, `null` is returned.
  </Accordion>

  <Accordion title="ST_REMOVEPOINT(geom, offset)" id="st_removepoint-geom-offset" defaultOpen>
    Remove a point from LINESTRING `geom` using `offset` to skip over POINTs in the LINESTRING. The
    `offset` is 0-based.
  </Accordion>

  <Accordion title="ST_REMOVEREPEATEDPOINTS (geom, tolerance)" id="st_removerepeatedpoints-geom-tolerance" defaultOpen>
    Removes points from `geom` if the point's vertices are greater than or equal to the `tolerance`
    of the previous point in the geometry's list. If `geom` is not a MULTIPOINT, MULTILINESTRING, or a
    MULTIPOLYGON, no points will be removed.
  </Accordion>

  <Accordion title="ST_REVERSE(geom)" id="st_reverse-geom" defaultOpen>
    Return the geometry with its coordinate order reversed.
  </Accordion>

  <Accordion title="ST_ROTATE(geom, radians[, wkt])" id="st_rotate-geom-radians-wkt" defaultOpen>
    Rotates `geom` counter-clockwise by `radians` radians.  Optionally, the rotation origin can be provided as a WKT POINT
    WKT POINT (`wkt`).  If not provided, `geom` will be rotated around *(0, 0)*.
  </Accordion>

  <Accordion title="ST_ROTATE(geom, radians[, x, y])" id="st_rotate-geom-radians-x-y" defaultOpen>
    Rotates `geom` counter-clockwise by `radians` radians.  Optionally, the rotation origin can be provided as a coordinate
    pair (`x` & `y`).  If not provided, `geom` will be rotated around *(0, 0)*.
  </Accordion>

  <Accordion title="ST_SCALE(geom, wkt)" id="st_scale-geom-wkt" defaultOpen>
    Scales `geom` by multiplying its respective vertices by the corresponding *x*, *y* values in the given WKT POINT.

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>ST\_SCALE('POLYGON((1 2, -2 1, -1 -2, 2 -1, 1 2))', GEOMETRY('POINT(3 5)'))</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>POLYGON ((3 10, -6 5, -3 -10, 6 -5, 3 10))</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="ST_SCALE(geom, x, y)" id="st_scale-geom-x-y" defaultOpen>
    Scales `geom` by multiplying its respective vertices by the given `x` & `y` values.

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>ST\_SCALE('POLYGON((1 2, -2 1, -1 -2, 2 -1, 1 2))', 3, 5)</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><code>POLYGON ((3 10, -6 5, -3 -10, 6 -5, 3 10))</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="ST_SEGMENTIZE (geom, max_segment_size[, solution])" id="st_segmentize-geom-max_segment_size-solution" defaultOpen>
    Returns the given `geom`, but segmentized *n* number of times depending on how the
    `max_segment_size` distance (in units based on the `solution` type) divides up the original
    geometry. The new `geom` is guaranteed to have segments that are smaller than the given
    `max_segment_size`. Note that POINTs are not able to be segmentized. Collection geometries
    (GEOMETRYCOLLECTION, MULTILINESTRING, MULTIPOINT, etc.) can be segmentized, but only the individual
    parts will be segmentized, not the collection as a whole. Solution types available:

    * `0` - Euclidean; uses degrees to calculate distance
    * `1` (default) - Sphere; uses meters to calculate distance
  </Accordion>

  <Accordion title="ST_SETPOINT(geom1, position, geom2)" id="st_setpoint-geom1-position-geom2" defaultOpen>
    Replace a point of LINESTRING `geom1` with POINT `geom2` at `position` (base 0). Negative
    values are valid, but note that they are counted backwards from the end of `geom`.
  </Accordion>

  <Accordion title="ST_SHAREDPATH(geom1, geom2)" id="st_sharedpath-geom1-geom2" defaultOpen>
    Returns a collection containing paths shared by `geom1` and `geom2`.
  </Accordion>

  <Accordion title="ST_SHORTESTLINE(geom1, geom2)" id="st_shortestline-geom1-geom2" defaultOpen>
    Returns the 2-D LINESTRING that represents the shortest line of points between the two geometries. If
    multiple shortest lines are found, only the first line found is returned. If `geom1` or `geom2`
    is empty, `null` is returned
  </Accordion>

  <Accordion title="ST_SIMPLIFY(geom, tolerance)" id="st_simplify-geom-tolerance" defaultOpen>
    Returns a simplified version of the given `geom` using an algorithm to reduce the number of points
    comprising a given geometry while attempting to best retain the original shape. The given
    `tolerance` determines how much to simplify the geometry. The higher the `tolerance`, the more
    simplified the returned geometry. Some holes might be removed and some invalid polygons (e.g.,
    self-intersecting, etc.) might be present in the returned geometry. Only (MULTI)LINESTRINGs and
    (MULTI)POLYGONs can be simplified, including those found within GEOMETRYCOLLECTIONs; any other
    geometry objects will be returned unsimplified.

    <Info>
      The `tolerance` should be provided in the same units as the data. As a rule of thumb,
      a `tolerance` of `0.00001` would correspond to about one meter.
    </Info>
  </Accordion>

  <Accordion title="ST_SIMPLIFYPRESERVETOPOLOGY (geom, tolerance)" id="st_simplifypreservetopology-geom-tolerance" defaultOpen>
    Returns a simplified version of the given `geom` using an algorithm to reduce the number of points
    comprising a given geometry while attempting to best retain the original shape. The given
    `tolerance` determines how much to simplify the geometry. The higher the `tolerance`, the more
    simplified the returned geometry. No holes will be removed and no invalid polygons (e.g.,
    self-intersecting, etc.) will be present in the returned geometry. Only (MULTI)LINESTRINGs and
    (MULTI)POLYGONs can be simplified, including those found within GEOMETRYCOLLECTIONs; any other
    geometry objects will be returned unsimplified.

    <Info>
      The `tolerance` should be provided in the same units as the data. As a rule of thumb,
      a `tolerance` of `0.00001` would correspond to about one meter.
    </Info>
  </Accordion>

  <Accordion title="ST_SNAP(geom1, geom2, tolerance)" id="st_snap-geom1-geom2-tolerance" defaultOpen>
    Snaps `geom1` to `geom2` within the given `tolerance`. If the `tolerance` causes `geom1`
    to not snap, the geometries will be returned unchanged.
  </Accordion>

  <Accordion title="ST_SPLIT(geom1, geom2)" id="st_split-geom1-geom2" defaultOpen>
    Returns a collection of geometries resulting from the split between `geom1` and `geom2`
    geometries.
  </Accordion>

  <Accordion title="ST_SQUAREGRID (xmin, ymin, xmax, ymax, cell_side[, limit])" id="st_squaregrid-xmin-ymin-xmax-ymax-cell_side-limit" defaultOpen>
    Creates a MULTIPOLYGON containing a grid of squares between given minimum and maximum points of a
    bounding box. The minimum point cannot be greater than or equal to the maximum point. The size (in
    meters) of the individual squares' sides is determined by `cell_side`. The `cell_side` cannot be
    greater than the width or height of the bounding box. The maximum number of cells that can be
    produced is determined by `limit`, a positive integer. Supported values for `limit`:

    * `-1` - No limit to the number of cells generated (effectively limited by system memory)
    * `0` (default) - 100 million cells
    * `<n>` - Custom limit of `n` cells

    If the custom limit request specifies more cells (based on the bounding box and the `cell_side`)
    than the system limit, a `null` is returned.
  </Accordion>

  <Accordion title="ST_STARTPOINT(geom)" id="st_startpoint-geom" defaultOpen>
    Returns the first point of LINESTRING `geom` as a POINT. Returns `null` if `geom` is not a
    LINESTRING.
  </Accordion>

  <Accordion title="ST_SYMDIFFERENCE(geom1, geom2)" id="st_symdifference-geom1-geom2" defaultOpen>
    Returns a geometry that represents the portions of `geom1` and `geom2` geometries that do not
    intersect.
  </Accordion>

  <Accordion title="ST_TOUCHES(geom1, geom2)" id="st_touches-geom1-geom2" defaultOpen>
    Returns `1` (true) if the given geometries, `geom1` and `geom2`, have at least one point in
    common but their interiors do not intersect. If `geom1` and/or `geom2` are a GEOMETRYCOLLECTION,
    a `0` is returned regardless of if the two geometries touch
  </Accordion>

  <Accordion title="ST_TRANSLATE (geom, deltax, deltay[, deltaz])" id="st_translate-geom-deltax-deltay-deltaz" defaultOpen>
    Translate `geom` by given offsets `deltax` and `deltay`. A z-coordinate offset can be applied
    using `deltaz`.
    intersect.
  </Accordion>

  <Accordion title="ST_TRIANGLEGRID (xmin, ymin, xmax, ymax, cell_side[, limit])" id="st_trianglegrid-xmin-ymin-xmax-ymax-cell_side-limit" defaultOpen>
    Creates a MULTIPOLYGON containing a grid of triangles between given minimum and maximum points of a
    bounding box. The minimum point cannot be greater than or equal to the maximum point. The size (in
    meters) of the individual triangles' sides is determined by `cell_side`. The `cell_side` cannot be
    greater than the width or height of the bounding box. The maximum number of cells that can be
    produced is determined by `limit`, a positive integer. Supported values for `limit`:

    * `-1` - No limit to the number of cells generated (effectively limited by system memory)
    * `0` (default) - 100 million cells
    * `<n>` - Custom limit of `n` cells

    If the custom limit request specifies more cells (based on the bounding box and the `cell_side`)
    than the system limit, a `null` is returned.
  </Accordion>

  <Accordion title="ST_UNION(geom1, geom2)" id="st_union-geom1-geom2" defaultOpen>
    Returns a geometry that represents the point set union of the two given geometries, `geom1` and
    `geom2`.
  </Accordion>

  <Accordion title="ST_UNIONCOLLECTION(geom)" id="st_unioncollection-geom" defaultOpen>
    Returns a geometry that represents the point set union of a single given geometry `geom`.
  </Accordion>

  <Accordion title="ST_UPDATE(geom1, geom2)" id="st_update-geom1-geom2" defaultOpen>
    Returns a geometry that is `geom1` geometry updated by `geom2` geometry
  </Accordion>

  <Accordion title="ST_VORONOIPOLYGONS(geom[, tolerance])" id="st_voronoipolygons-geom-tolerance" defaultOpen>
    Returns a GEOMETRYCOLLECTION containing Voronoi polygons (regions consisting of points closer to
    a vertex in `geom` than any other vertices in `geom`) calculated from the vertices in `geom`
    and the given `tolerance`. The `tolerance` determines the distance at which points will be
    considered the same.  An empty GEOMETRYCOLLECTION is returned if `geom` is an empty geometry, a
    single POINT, or a LINESTRING or POLYGON composed of equivalent vertices (e.g.,
    `POLYGON((0 0, 0 0, 0 0, 0 0))`, `LINESTRING(0 0, 0 0)`).

    If no `tolerance` is specified, no vertices will be considered the same; each will have its own polygon.

    The bounding box for the result POLYGONs extends past the four edges of the input `geom` bounding box by
    an amount that is the greater of the input bounding box's height and width.  For instance, an input `geom`
    with a *3* x *4* bounding box will result in Voronoi polygons filling a space that is *11* x *12*.
  </Accordion>

  <Accordion title="ST_WITHIN(geom1, geom2)" id="st_within-geom1-geom2" defaultOpen>
    Returns `1` (true) if the `geom1` geometry is inside the `geom2` geometry. Note that as long as
    at least one point is inside of `geom2`, `geom1` is considered within `geom2` even if the rest
    of the `geom1` lies along the boundary of `geom2`
  </Accordion>

  <Accordion title="ST_WKBTOWKT(geom)" id="st_wkbtowkt-geom" defaultOpen>
    Returns the text form (WKT) of a geometry from the given byte form (WKB)
  </Accordion>

  <Accordion title="ST_WKTTOWKB(geom)" id="st_wkttowkb-geom" defaultOpen>
    Returns the byte form (WKB) of a geometry from the given text form (WKT)
  </Accordion>

  <Accordion title="ST_X(geom)" id="st_x-geom" defaultOpen>
    Returns the X coordinate of the POINT `geom`; if the coordinate is not available, `null` is
    returned. `geom` must be a POINT.
  </Accordion>

  <Accordion title="ST_XMAX(geom)" id="st_xmax-geom" defaultOpen>
    Alias for `ST_MAXX()`
  </Accordion>

  <Accordion title="ST_XMIN(geom)" id="st_xmin-geom" defaultOpen>
    Alias for `ST_MINX()`
  </Accordion>

  <Accordion title="ST_Y(geom)" id="st_y-geom" defaultOpen>
    Returns the Y coordinate of the POINT `geom`; if the coordinate is not available, `null` is
    returned. `geom` must be a POINT.
  </Accordion>

  <Accordion title="ST_YMAX(geom)" id="st_ymax-geom" defaultOpen>
    Alias for `ST_MAXY()`
  </Accordion>

  <Accordion title="ST_YMIN(geom)" id="st_ymin-geom" defaultOpen>
    Alias for `ST_MINY()`
  </Accordion>

  <Accordion title="ST_ZMAX(geom)" id="st_zmax-geom" defaultOpen>
    Alias for `ST_MAXZ()`
  </Accordion>

  <Accordion title="ST_ZMIN(geom)" id="st_zmin-geom" defaultOpen>
    Alias for `ST_MINZ()`
  </Accordion>
</AccordionGroup>

<a id="sql-geo-functions-aggregation" />

### Aggregation Functions

The following functions can be used on geospatial/geometry columns within
[aggregations](/content/sql/query#sql-aggregation).

<AccordionGroup>
  <Accordion title="ST_AGGREGATE_COLLECT(geom)" id="st_aggregate_collect-geom" defaultOpen>
    Alias for `ST_COLLECT_AGGREGATE()`
  </Accordion>

  <Accordion title="ST_AGGREGATE_INTERSECTION(geom)" id="st_aggregate_intersection-geom" defaultOpen>
    Alias for `ST_INTERSECTION_AGGREGATE()`
  </Accordion>

  <Accordion title="ST_COLLECT_AGGREGATE(geom)" id="st_collect_aggregate-geom" defaultOpen>
    Returns a GEOMETRYCOLLECTION comprising all geometries found in the `geom` set.
    Any MULTI\* geometries will be divided into separate singular geometries, e.g.,
    MULTIPOINT((0 0), (1 1)) would be divided into POINT(0 0) and POINT(1 1) in the
    results; the same is true for elements of a GEOMETRYCOLLECTION found in `geom`,
    where a GEOMETRYCOLLECTION within the provided `geom` set will also be parsed,
    effectively flattening it and adding the individual geometries to the resulting
    GEOMETRYCOLLECTION. Any empty geometries in `geom` are ignored even if they are
    part of a GEOMETRYCOLLECTION. Any duplicate WKTs will be retained.
  </Accordion>

  <Accordion title="ST_DISSOLVE(geom)" id="st_dissolve-geom" defaultOpen>
    Dissolves all geometries within a given set into a single geometry. Note that the
    resulting single geometry can still be a group of noncontiguous geometries but
    represented as a single group, e.g., a GEOMETRYCOLLECTION.  Best performance when
    used in conjunction with adjacent geometries.
  </Accordion>

  <Accordion title="ST_DISSOLVEOVERLAPPING(geom)" id="st_dissolveoverlapping-geom" defaultOpen>
    Dissolves all geometries within a given set into a single geometry. Note that the
    resulting single geometry can still be a group of noncontiguous geometries but
    represented as a single group, e.g., a GEOMETRYCOLLECTION.  Best performance when
    used in conjunction with overlapping geometries.
  </Accordion>

  <Accordion title="ST_INTERSECTION_AGGREGATE(geom)" id="st_intersection_aggregate-geom" defaultOpen>
    Returns a POLYGON or MULTIPOLYGON comprising the shared portion between all
    geometries found in the `geom` set.  Returns an empty GEOMETRYCOLLECTION if
    there is no shared portion between all geometries. Functionally equivalent to
    `ST_INTERSECTION(ST_INTERSECTION(geom1, geom2), ... geomN)`.
  </Accordion>

  <Accordion title="ST_LINESTRINGFROMORDEREDPOINTS(x, y, t)" id="st_linestringfromorderedpoints-x-y-t" defaultOpen>
    Returns a LINESTRING that represents a "track" of the given points (`x`, `y`)
    ordered by the given sort column `t` (e.g., a timestamp or sequence number). If
    any of the values in the specified columns are `null`, the null "point" will be
    left out of the resulting LINESTRING. If there's only one non-null "point" in the
    source table, a POINT is returned. If there are no non-null "points" in the
    source table, a `null` is returned.
  </Accordion>

  <Accordion title="ST_LINESTRINGFROMORDEREDPOINTS3D(x, y, z, t)" id="st_linestringfromorderedpoints3d-x-y-z-t" defaultOpen>
    Returns a LINESTRING that represents a "track" of the given 3D points
    (`x`, `y`, `z`) ordered by the given sort column `t` (e.g., a timestamp
    or sequence number). If any of the values in the specified columns are `null`,
    the null "point" will be left out of the resulting LINESTRING. If there's only
    one non-null "point" in the source table, a POINT is returned. If there are no
    non-null "points" in the source table, a `null` is returned.
  </Accordion>

  <Accordion title="ST_POLYGONIZE(geom)" id="st_polygonize-geom" defaultOpen>
    Returns a GEOMETRYCOLLECTION containing POLYGONs comprising the provided
    (MULTI)LINESTRING(s). (MULTI)POINT and (MULTI)POLYGON geometries are ignored when
    calculating the resulting GEOMETRYCOLLECTION. If a valid POLYGON cannot be
    constructed from the provided (MULTI)LINESTRING(s), an empty GEOMETRYCOLLECTION
    will be returned.
  </Accordion>
</AccordionGroup>

<a id="sql-geo-functions-track" />

### Track Functions

The following functions are available in both SQL and the native API.

<AccordionGroup>
  <Accordion title="ST_TRACKDURATION([unit,] t)" id="st_trackduration-unit-t" defaultOpen>
    Returns the total time, in the given `unit`, spanned by timestamp values in column
    `t`.  Grouping by *track* ID will return the duration per *track*.

    The duration can be returned in any of the following date/time units:

    * `YEAR`
    * `MONTH`
    * `DAY`
    * `HOUR`
    * `MINUTE`
    * `SECOND`
    * `MILLISECOND`

    The default `unit` is `MILLISECOND`.
  </Accordion>

  <Accordion title="ST_TRACKLENGTH(lat, lon, t[, solution])" id="st_tracklength-lat-lon-t-solution" defaultOpen>
    Returns the total length of the track whose position values are specified by `lat` &
    `lon` and whose ordering is determined by an ascending sort on the timestamp `t`.
    Length can be returned with any of the following solution types:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Type</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>0</code></td>
            <td>2D Euclidean length in degrees</td>
          </tr>

          <tr>
            <td><code>1</code></td>
            <td>(default) Length on a sphere in meters</td>
          </tr>

          <tr>
            <td><code>2</code></td>
            <td>Length on a spheroid in meters</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>
</AccordionGroup>

#### ST\_TRACK\_DWITHIN

The `ST_TRACK_DWITHIN` table function finds tracks that are related, within
spatial or temporal bounds (or both) to the given track(s).  The track(s) to use
as the filter criteria will be specified by the `SEARCH_*` parameters.  The
`TRACK_*` parameters specify the set of tracks to search through for a match.

<Info>
  This function is only available in SQL or in the native API via
  [/execute/sql](/content/api/rest/execute_sql_rest).
</Info>

The basic form of the `ST_TRACK_DWITHIN` function follows.

```sql ST_TRACK_DWITHIN Table Function Syntax theme={null}
SELECT *
FROM TABLE
(
    ST_TRACK_DWITHIN
    (
        TRACK_TABLE => INPUT_TABLE(<table name | select statement>),
        TRACK_ID_COLUMN => < '<column name>' | <column position> >,
        TRACK_X_COLUMN => < '<column name>' | <column position> >,
        TRACK_Y_COLUMN => < '<column name>' | <column position> >,
        TRACK_ORDER_COLUMN => < '<column name>' | <column position> >,
        SEARCH_TABLE => INPUT_TABLE(<table name | select statement>),
        SEARCH_ID_COLUMN => < '<column name>' | <column position> >,
        SEARCH_X_COLUMN => < '<column name>' | <column position> >,
        SEARCH_Y_COLUMN => < '<column name>' | <column position> >,
        SEARCH_ORDER_COLUMN => < '<column name>' | <column position> >,
        [
            SEARCH_XY_DISTANCE => '<spatial distance with unit>',
            SPATIAL_SOLUTION_TYPE => <solution type>,
            SEARCH_TIME_DISTANCE => '<temporal distance with unit>'
        ]
    )
)
```

<AccordionGroup>
  <Accordion title="TRACK_TABLE" id="track_table" defaultOpen>
    Name of the table to search for tracks matching the track(s) specified in the `SEARCH_*` data set.

    To perform a search on the *flights* table, pass the name of the table to `INPUT_TABLE`:

    ```
    INPUT_TABLE(flights)
    ```

    To perform a search on the result of a query, pass the query to `INPUT_TABLE`:

    ```
    INPUT_TABLE
    (
        SELECT * FROM flights_west
        UNION
        SELECT * FROM flights_east
    )
    ```
  </Accordion>

  <Accordion title="TRACK_ID_COLUMN" id="track_id_column" defaultOpen>
    Table to search track column, containing the unique identifier for the track to which each track point
    belongs.
  </Accordion>

  <Accordion title="TRACK_X_COLUMN" id="track_x_column" defaultOpen>
    Table to search track column, containing the longitude value of each track point.
  </Accordion>

  <Accordion title="TRACK_Y_COLUMN" id="track_y_column" defaultOpen>
    Table to search track column, containing the latitude value of each track point.
  </Accordion>

  <Accordion title="TRACK_ORDER_COLUMN" id="track_order_column" defaultOpen>
    Table to search track column, by which the searched track points will be sorted in ascending order.
  </Accordion>

  <Accordion title="SEARCH_TABLE" id="search_table" defaultOpen>
    Name of the search criteria track table, containing the track(s) to be used as the filter criteria
    when searching for matching tracks in the `TRACK_*` data set.

    To match tracks from the *flights\_of\_interest* table, pass the name of the table to `INPUT_TABLE`:

    ```
    INPUT_TABLE(flights_of_interest)
    ```

    To match tracks from the result of a query, pass the query to `INPUT_TABLE`:

    ```
    INPUT_TABLE
    (
        SELECT * FROM flights_of_interest_west
        UNION
        SELECT * FROM flights_of_interest_east
    )
    ```
  </Accordion>

  <Accordion title="SEARCH_ID_COLUMN" id="search_id_column" defaultOpen>
    Search criteria track column, containing the unique identifier for the track to which each track point
    belongs.
  </Accordion>

  <Accordion title="SEARCH_X_COLUMN" id="search_x_column" defaultOpen>
    Search criteria track column, containing the longitude value of each track point.
  </Accordion>

  <Accordion title="SEARCH_Y_COLUMN" id="search_y_column" defaultOpen>
    Search criteria track column, containing the latitude value of each track point.
  </Accordion>

  <Accordion title="SEARCH_ORDER_COLUMN" id="search_order_column" defaultOpen>
    Search criteria track column, by which the filter track points will be sorted in ascending order.
  </Accordion>

  <Accordion title="SEARCH_XY_DISTANCE" id="search_xy_distance" defaultOpen>
    The radius around the given tracks to search for matching tracks.

    <Note>
      This parameter is not applicable when using a `SPATIAL_SOLUTION_TYPE` of `0`.
    </Note>

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Unit</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>f</code></td>
            <td>Feet</td>
          </tr>

          <tr>
            <td><code>ki</code></td>
            <td>Kilometers</td>
          </tr>

          <tr>
            <td><code>m</code></td>
            <td>(default) Meters</td>
          </tr>

          <tr>
            <td><code>mi</code></td>
            <td>Miles</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="SPATIAL_SOLUTION_TYPE" id="spatial_solution_type" defaultOpen>
    Spatial match solution type; any of the following:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Type</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>0</code></td>
            <td>(default) 2D Euclidean length in degrees</td>
          </tr>

          <tr>
            <td><code>1</code></td>
            <td>Length on a sphere, returned in units specified by <code>SEARCH\_XY\_DISTANCE</code></td>
          </tr>

          <tr>
            <td><code>2</code></td>
            <td>Length on a spheroid, returned in units specified by <code>SEARCH\_XY\_DISTANCE</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="SEARCH_TIME_DISTANCE" id="search_time_distance" defaultOpen>
    The maximum allowable time difference between a search criteria track's point and a matched track's
    points.  The time can use any of the following suffices for units:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Unit</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>ms</code></td>
            <td>Milliseconds</td>
          </tr>

          <tr>
            <td><code>s</code></td>
            <td>(default) Seconds</td>
          </tr>

          <tr>
            <td><code>m</code></td>
            <td>Minutes</td>
          </tr>

          <tr>
            <td><code>h</code></td>
            <td>Hours</td>
          </tr>

          <tr>
            <td><code>d</code></td>
            <td>Days</td>
          </tr>

          <tr>
            <td><code>w</code></td>
            <td>Weeks</td>
          </tr>

          <tr>
            <td><code>months</code></td>
            <td>Months</td>
          </tr>

          <tr>
            <td><code>y</code></td>
            <td>Years</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>
</AccordionGroup>

To see the matches between a set of flights and a given set of flights of
interest:

```sql ST_TRACK_DWITHIN Example theme={null}
SELECT *
FROM TABLE
(
	ST_TRACK_DWITHIN
	(
		TRACK_TABLE => INPUT_TABLE(example_geospatial.flights),
		TRACK_ID_COLUMN => 'id',
		TRACK_X_COLUMN => 'lon',
		TRACK_Y_COLUMN => 'lat',
		TRACK_ORDER_COLUMN => 'flight_time',
		SEARCH_TABLE => INPUT_TABLE
						(
							SELECT id, lon, lat, flight_time
							FROM example_geospatial.flights_northwest
							UNION
							SELECT id, lon, lat, flight_time
							FROM example_geospatial.flights_northeast
						),
		SEARCH_ID_COLUMN => 1,
		SEARCH_X_COLUMN => 2,
		SEARCH_Y_COLUMN => 3,
		SEARCH_ORDER_COLUMN => 4,
		SEARCH_TIME_DISTANCE => '5m',
		SEARCH_XY_DISTANCE => '1km',
		SPATIAL_SOLUTION_TYPE => 1
	)
)
```

#### ST\_TRACKINTERSECTS

The `ST_TRACKINTERSECTS` table function finds tracks pass through the given
geofence(s).  The geofence(s) use as the filter will be specified by the
`GEOFENCE_*` parameters.  The `TRACK_*` parameters specify the set of
tracks to search through for any intersecting the geofence(s).

The result will include a record for each intersecting track & geofence pair,
with:

* a `LINESTRING` representing the full track intersecting a geofence
* a `LINESTRING` representing the geofence it intersected

<Info>
  This function is only available in SQL or in the native API via
  [/execute/sql](/content/api/rest/execute_sql_rest).
</Info>

The basic form of the `ST_TRACKINTERSECTS` function follows.

```sql ST_TRACKINTERSECTS Table Function Syntax theme={null}
SELECT *
FROM TABLE
(
    ST_TRACKINTERSECTS
    (
        TRACK_TABLE => INPUT_TABLE(<table name | select statement>),
        TRACK_ID_COLUMN => < '<column name>' | <column position> >,
        TRACK_X_COLUMN => < '<column name>' | <column position> >,
        TRACK_Y_COLUMN => < '<column name>' | <column position> >,
        TRACK_ORDER_COLUMN => < '<column name>' | <column position> >,
        GEOFENCE_TABLE => INPUT_TABLE(<table name | select statement>),
        GEOFENCE_ID_COLUMN => < '<column name>' | <column position> >,
        GEOFENCE_WKT_COLUMN => < '<column name>' | <column position> >
    )
)
```

<AccordionGroup>
  <Accordion title="TRACK_TABLE" id="track_table-2" defaultOpen>
    Name of the table to search for tracks intersecting the geofence(s) specified in the `SEARCH_*` data
    set.

    To perform a search on the *flights* table, pass the name of the table to `INPUT_TABLE`:

    ```
    INPUT_TABLE(flights)
    ```

    To perform a search on the result of a query, pass the query to `INPUT_TABLE`:

    ```
    INPUT_TABLE
    (
        SELECT * FROM flights_west
        UNION
        SELECT * FROM flights_east
    )
    ```
  </Accordion>

  <Accordion title="TRACK_ID_COLUMN" id="track_id_column-2" defaultOpen>
    Table to search track column, containing the unique identifier for the track to which each track point
    belongs.
  </Accordion>

  <Accordion title="TRACK_X_COLUMN" id="track_x_column-2" defaultOpen>
    Table to search track column, containing the longitude value of each track point.
  </Accordion>

  <Accordion title="TRACK_Y_COLUMN" id="track_y_column-2" defaultOpen>
    Table to search track column, containing the latitude value of each track point.
  </Accordion>

  <Accordion title="TRACK_ORDER_COLUMN" id="track_order_column-2" defaultOpen>
    Table to search track column, by which the searched track points will be sorted in ascending order.
  </Accordion>

  <Accordion title="GEOFENCE_TABLE" id="geofence_table" defaultOpen>
    Name of the geofence table, containing the WKT(s) to be used as the filter criteria when searching for
    intersecting tracks in the `TRACK_*` data set.

    To search for tracks intersecting the geofence(s) from the *flight\_area\_of\_interest* table, pass the
    name of the geofence table to `INPUT_TABLE`:

    ```
    INPUT_TABLE(flight_area_of_interest)
    ```

    To search for tracks intersecting the geofence(s) from the result of a query, pass the query to
    `INPUT_TABLE`:

    ```
    INPUT_TABLE
    (
        SELECT * FROM flight_area_of_interest_west
        UNION
        SELECT * FROM flight_area_of_interest_east
    )
    ```
  </Accordion>

  <Accordion title="GEOFENCE_ID_COLUMN" id="geofence_id_column" defaultOpen>
    Geofence column, containing the unique identifier for the geofence.
  </Accordion>

  <Accordion title="GEOFENCE_WKT_COLUMN" id="geofence_wkt_column" defaultOpen>
    Geofence column, containing the WKT bounds of the geofence.
  </Accordion>
</AccordionGroup>

To see the intersections between a set of flights and an area of interest:

```sql ST_TRACKINTERSECTS Example theme={null}
SELECT *
FROM TABLE
(
	ST_TRACKINTERSECTS
	(
		TRACK_TABLE =>         INPUT_TABLE(example_geospatial.flights),
		TRACK_ID_COLUMN =>     'id',
		TRACK_X_COLUMN =>      'lon',
		TRACK_Y_COLUMN =>      'lat',
		TRACK_ORDER_COLUMN =>  'flight_time',
		GEOFENCE_TABLE =>      INPUT_TABLE(example_geospatial.track_geofence),
		GEOFENCE_ID_COLUMN =>  'fence_name',
		GEOFENCE_WKT_COLUMN => 'fence_wkt'
	)
)
ORDER BY id, fence_name
```

<a id="sql-geo-functions-h3" />

### H3 Functions

The functions below support various operations using the H3 geospatial indexing scheme.

<AccordionGroup>
  <Accordion title="H3_CELLTOBOUNDARY(h3_index)" id="h3_celltoboundary-h3_index" defaultOpen>
    Returns a POLYGON boundary box of the H3 index identified by the given `h3_index`.

    See [Geohash-H3](/content/snippets/geohash-h3) for an example.
  </Accordion>

  <Accordion title="H3_CELLTOCENTERCHILD(h3_index, res)" id="h3_celltocenterchild-h3_index-res" defaultOpen>
    Alias for `H3_CELLTOFIRSTCHILD`.
  </Accordion>

  <Accordion title="H3_CELLTOCHILDN(h3_index, res, i)" id="h3_celltochildn-h3_index-res-i" defaultOpen>
    Returns the H3 index corresponding to the 0-based `i` th child at resolution `res` for the given
    `h3_index`.  The value `i` should be less than the number of children returned from calling
    `H3_CELLTOCHILDRENSIZE(h3_index, res)`.
  </Accordion>

  <Accordion title="H3_CELLTOCHILDPOS(h3_index, res)" id="h3_celltochildpos-h3_index-res" defaultOpen>
    Returns the position of the given `h3_index` within an ordered list of the children of the cell's
    parent at resolution `res`. This is the inverse of `H3_CHILDPOSTOCELL` (`H3_CELLTOCHILDN`).
  </Accordion>

  <Accordion title="H3_CELLTOCHILDRENSIZE(h3_index, res)" id="h3_celltochildrensize-h3_index-res" defaultOpen>
    Returns the number of child cells at resolution `res` for the given `h3_index`.
  </Accordion>

  <Accordion title="H3_CELLTOFIRSTCHILD(h3_index, res)" id="h3_celltofirstchild-h3_index-res" defaultOpen>
    Returns the H3 index corresponding to the first child at resolution `res` for the given `h3_index`.

    This is equivalent to `H3_CELLTOCHILDN(h3_index,res,0)`.
  </Accordion>

  <Accordion title="H3_CELLTOLASTCHILD(h3_index, res)" id="h3_celltolastchild-h3_index-res" defaultOpen>
    Returns the H3 index corresponding to the last child at resolution `res` for the given `h3_index`.

    This is equivalent to `H3_CELLTOCHILDN(h3_index,res,H3_CELLTOCHILDRENSIZE(h3_index, res)-1)`.
  </Accordion>

  <Accordion title="H3_CELLTOPARENT(h3_index, res)" id="h3_celltoparent-h3_index-res" defaultOpen>
    Returns the H3 index corresponding to the parent cell of the given `h3_index` at resolution `res`.
  </Accordion>

  <Accordion title="H3_CELLTOXY(h3_index)" id="h3_celltoxy-h3_index" defaultOpen>
    Returns a WKT POINT corresponding to the centroid of the given `h3_index`.
  </Accordion>

  <Accordion title="H3_CHILDPOSTOCELL(i, h3_index, res)" id="h3_childpostocell-i-h3_index-res" defaultOpen>
    Alias for `H3_CELLTOCHILDN(h3_index, res, i)`.
  </Accordion>

  <Accordion title="H3_GEOMTOCELL(geom, res)" id="h3_geomtocell-geom-res" defaultOpen>
    Returns the H3 index, similar to a geohash, for the cell containing the centroid of the geometry
    `geom` with the given resolution `res`.  The higher the resolution, the more precise the index
    is. The resolution `res` must be an integer between `0` and `15`.

    See [Geohash-H3](/content/snippets/geohash-h3) for an example.
  </Accordion>

  <Accordion title="H3_GETRESOLUTION(h3_index)" id="h3_getresolution-h3_index" defaultOpen>
    Returns the resolution of the H3 index `h3_index`.
  </Accordion>

  <Accordion title="H3_GRIDDISK(h3_index, k)" id="h3_griddisk-h3_index-k" defaultOpen>
    Returns an array of H3 indexes within a given distance `k` from the provided H3 index `h3_index`.
  </Accordion>

  <Accordion title="H3_GRIDDISKN(h3_index, k, i)" id="h3_griddiskn-h3_index-k-i" defaultOpen>
    Returns the `i` <sup>th</sup> H3 index within a given distance `k` from the provided H3 index
    `h3_index`.  This function would typically be used in conjunction with `H3_NUMGRIDDISK` via iter-join.
    The value of `i` should be between `0` and the result of `H3_NUMGRIDDISK(h3_index, k)` - `1`.
  </Accordion>

  <Accordion title="H3_GRIDRING(h3_index, k)" id="h3_gridring-h3_index-k" defaultOpen>
    Returns an array of H3 indexes comprising a hollow ring at a distance `k` from the provided
    H3 index `h3_index`.
  </Accordion>

  <Accordion title="H3_H3TOSTRING(h3_index)" id="h3_h3tostring-h3_index" defaultOpen>
    Returns the string representation of the H3 index `h3_index`.

    <Info>
      This function is the inverse of `H3_STRINGTOH3`.
    </Info>
  </Accordion>

  <Accordion title="H3_ISVALID(h3_index)" id="h3_isvalid-h3_index" defaultOpen>
    Returns `1` (true) if the given H3 index `h3_index` is a valid H3 index value; otherwise
    returns `0` (false).
  </Accordion>

  <Accordion title="H3_LATLNGTOCELL (latitude, longitude, res)" id="h3_latlngtocell-latitude-longitude-res" defaultOpen>
    Returns the H3 index, similar to a geohash, for the cell containing the `latitude` and `longitude`
    coordinate, with the given resolution `res`.  The higher the resolution, the more precise the index
    is. The resolution `res` must be an integer between `0` and `15`.

    Equivalent to `H3_XYTOCELL(longitude, latitude, res)`.
  </Accordion>

  <Accordion title="H3_NUMGRIDDISK(h3_index, k)" id="h3_numgriddisk-h3_index-k" defaultOpen>
    Returns the number of cells at a distance of `k` from the provided H3 index `h3_index`. This function
    would typically be used in conjunction with `H3_GRIDDISKN` via iter-join.
  </Accordion>

  <Accordion title="H3_NUMPOLYGONTOCELLS(geom, res)" id="h3_numpolygontocells-geom-res" defaultOpen>
    Returns the number of cells at the given resolution `res` that are within the given geometry `geom`.
    Only polygon geometries are supported. This function would typically be used in conjunction with
    `H3_POLYGONTOCELLSN` via iter-join.
  </Accordion>

  <Accordion title="H3_POLYGONTOCELLS(geom, res)" id="h3_polygontocells-geom-res" defaultOpen>
    Returns an array of H3 indexes at the given resolution `res` that are within the given geometry `geom`.
    Only polygon geometries are supported.
  </Accordion>

  <Accordion title="H3_POLYGONTOCELLSN(geom, res, i)" id="h3_polygontocellsn-geom-res-i" defaultOpen>
    Returns the `i` <sup>th</sup> H3 index at the given resolution `res` that is within the given geometry
    `geom`.  Only polygon geometries are supported. This function would typically be used in conjunction with
    `H3_NUMPOLYGONTOCELLS` via iter-join. The value of `i` should be between `0` and the value returned
    from `H3_NUMPOLYGONTOCELLS(geom, res)` - `1`.
  </Accordion>

  <Accordion title="H3_STRINGTOH3(h3_string)" id="h3_stringtoh3-h3_string" defaultOpen>
    Returns the H3 index corresponding to the string representation `h3_string`.

    <Info>
      This function is the inverse of `H3_H3TOSTRING`.
    </Info>
  </Accordion>

  <Accordion title="H3_XYTOCELL(x, y, res)" id="h3_xytocell-x-y-res" defaultOpen>
    Returns the H3 index, similar to a geohash, for the cell containing the `x` and `y` coordinate,
    with the given resolution `res`.  The higher the resolution, the more precise the index is. The
    resolution `res` must be an integer between `0` and `15`.

    Equivalent to `H3_LATLNGTOCELL(y, x, res)`.

    See [Geohash-H3](/content/snippets/geohash-h3) for an example.
  </Accordion>
</AccordionGroup>

<a id="sql-json-functions" />

## JSON Functions

<a id="sql-json-functions-scalar" />

### Scalar Functions

These functions can be applied to individual *json* column values, as well as
*array* & *string* columns.  However, for some functions to work as expected,
the *array* or *string* value may need to be cast to JSON first.

<AccordionGroup>
  <Accordion title="JSON(expr)" id="json-expr" defaultOpen>
    Casts the given `expr` to JSON data type

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON('\[1, 2, "C"]')</code></td>
            <td><code>\[1,2,"C"]</code></td>
          </tr>

          <tr>
            <td><code>JSON('\{"A": "B", "C": \{"D": 5, "F": 7}}')</code></td>
            <td><code>\{"A":"B","C":\{"D":5,"F":7}}</code></td>
          </tr>

          <tr>
            <td><code>JSON(null)</code></td>
            <td>*null*</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_ARRAY (value[,...] <null_hand>)" id="json_array-value-<null_hand>" defaultOpen>
    Creates a JSON array out of the given list of values.

    An optional `<null_hand>` parameter can be added to the end of the list to specify
    handling of *null* values, though, at present, this only exists for compatibility with
    other databases' syntax--the option will be ignored and all *null* values will be added
    to the array as *null*.  Accepted null handling options:

    * `NULL ON NULL`

    <Info>
      This function is only available in SQL or in the native API via
      [/execute/sql](/content/api/rest/execute_sql_rest).
    </Info>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_ARRAY(1, 2, 'C')</code></td>
            <td><code>\[1,2,"C"]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_ARRAY(JSON('\{"A": "B"}'), JSON('\{"C": 4}'))</code></td>
            <td><code>\[\{"A":"B"},\{"C":4}]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_ARRAY(1, null, 'C' NULL ON NULL)</code></td>
            <td><code>\[1,null,"C"]</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_ARRAY_APPEND(arr, value)" id="json_array_append-arr-value" defaultOpen>
    Appends the given `value` to the given array `arr` of type string, array, or JSON

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_ARRAY\_APPEND('\[1, 2]', 'C')</code></td>
            <td><code>\[1,2,"C"]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_ARRAY\_APPEND('\{"A": "B"}', JSON('\{"C": 4}'))</code></td>
            <td><code>\[\{"A":"B"},\{"C":4}]</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_ARRAY_CONTAINS (json, path, val)" id="json_array_contains-json-path-val" defaultOpen>
    Returns whether the given JSON `json` contains the primitive value `val` at the JSON
    query path, `path`

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_ARRAY\_CONTAINS('\[1, 2]', '\$', 2)</code></td>
            <td><code>true</code></td>
          </tr>

          <tr>
            <td><code>JSON\_ARRAY\_CONTAINS('\[1, 2]', '\$', 'C')</code></td>
            <td><code>false</code></td>
          </tr>

          <tr>
            <td><code>JSON\_ARRAY\_CONTAINS('\{"A": \[2, 3]}', '\$.A', 2)</code></td>
            <td><code>true</code></td>
          </tr>

          <tr>
            <td><code>JSON\_ARRAY\_CONTAINS('\{"A": \{"B": \[3, 4]}}', '\$\["A"]\["B"]', 4)</code></td>
            <td><code>true</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_CARDINALITY(json)" id="json_cardinality-json" defaultOpen>
    Alias for `JSON_LENGTH`
  </Accordion>

  <Accordion title="JSON_EXISTS(json, path)" id="json_exists-json-path" defaultOpen>
    Returns whether the given JSON `json` contains the JSON query path, `path`

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_EXISTS('\[1, 2]', '\$')</code></td>
            <td><code>true</code></td>
          </tr>

          <tr>
            <td><code>JSON\_EXISTS('\[1, 2]', '\$.A')</code></td>
            <td><code>false</code></td>
          </tr>

          <tr>
            <td><code>JSON\_EXISTS('\{"A": \[2, 3]}', '\$.A')</code></td>
            <td><code>true</code></td>
          </tr>

          <tr>
            <td><code>JSON\_EXISTS('\{"A": \{"B": 3, "D": 5}}', '\$\["A"]\["D"]')</code></td>
            <td><code>true</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_KEYS(json, path)" id="json_keys-json-path" defaultOpen>
    Returns the set of keys of the JSON object at the given `path` in `json`; null, if the
    path doesn't exist or contains a non-object (non-map) value

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_KEYS('\{}', '\$')</code></td>
            <td><code>\[]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_KEYS('\[1, 2]', '\$.A')</code></td>
            <td>*null*</td>
          </tr>

          <tr>
            <td><code>JSON\_KEYS('\{"A": \[2, 3]}', '\$')</code></td>
            <td><code>\["A"]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_KEYS('\{"A": \{"B": 3, "D": 5}}', '\$\["A"]')</code></td>
            <td><code>\["B","D"]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_KEYS('\{"A": \{"B": 3, "D": 5}}', '\$\["A"]\["D"]')</code></td>
            <td>*null*</td>
          </tr>

          <tr>
            <td><code>JSON\_KEYS('\{"A": \{"B": 3, "D": \{}}}', '\$\["A"]\["D"]')</code></td>
            <td><code>\[]</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_LENGTH(json[, path])" id="json_length-json-path" defaultOpen>
    Returns the number of items in the top-level object of the given `json`, or at the
    level of the optional JSON `path`

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_LENGTH('\{}')</code></td>
            <td><code>0</code></td>
          </tr>

          <tr>
            <td><code>JSON\_LENGTH('\[]')</code></td>
            <td><code>0</code></td>
          </tr>

          <tr>
            <td><code>JSON\_LENGTH('\[1, 2]')</code></td>
            <td><code>2</code></td>
          </tr>

          <tr>
            <td><code>JSON\_LENGTH('\{"A": \[2, 3]}')</code></td>
            <td><code>1</code></td>
          </tr>

          <tr>
            <td><code>JSON\_LENGTH('\{"A": \{"B": 3}, "D": "E"}')</code></td>
            <td><code>2</code></td>
          </tr>

          <tr>
            <td><code>JSON\_LENGTH('\{"A": \[2, 3]}', '\$.A')</code></td>
            <td><code>2</code></td>
          </tr>

          <tr>
            <td><code>JSON\_LENGTH('\{"A": \{"B": 3}, "D": "E"}', '\$.A')</code></td>
            <td><code>1</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_MAKE_ARRAY(value)" id="json_make_array-value" defaultOpen>
    Creates a JSON array out of the given `value`

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_MAKE\_ARRAY(1)</code></td>
            <td><code>\[1]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_MAKE\_ARRAY(JSON\_ARRAY(1,2,3))</code></td>
            <td><code>\[\[1,2,3]]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_MAKE\_ARRAY(JSON('\{"A": "B"}'))</code></td>
            <td><code>\[\{"A":"B"}]</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_OBJECT (value[,...] <null_hand>)" id="json_object-value-<null_hand>" defaultOpen>
    Creates a JSON map out of the given `value` set

    An optional `<null_hand>` parameter can be added to the end of the list to specify
    handling of *null* values, though, at present, this only exists for compatibility with
    other databases' syntax--the option will be ignored and all *null* values will be added
    to the array as *null*.  Accepted null handling options:

    * `NULL ON NULL`

    <Info>
      This function is only available in SQL or in the native API via
      [/execute/sql](/content/api/rest/execute_sql_rest).
    </Info>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_OBJECT()</code></td>
            <td><code>\{}</code></td>
          </tr>

          <tr>
            <td><code>JSON\_OBJECT('A': 2)</code></td>
            <td><code>\{"A":2}</code></td>
          </tr>

          <tr>
            <td><code>JSON\_OBJECT('A' VALUE 2)</code></td>
            <td><code>\{"A":2}</code></td>
          </tr>

          <tr>
            <td><code>JSON\_OBJECT(KEY 'A' VALUE 2)</code></td>
            <td><code>\{"A":2}</code></td>
          </tr>

          <tr>
            <td><code>JSON\_OBJECT('A': 'B', 'C': null NULL ON NULL)</code></td>
            <td><code>\{"A":"B","C":null}</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_PRETTY(json)" id="json_pretty-json" defaultOpen>
    Returns a formatted version of the given `json` object

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>JSON\_PRETTY('\[1,2,"C"]')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><pre><code>\[
            1,
            2,
            "C"
            ]</code></pre></td>
          </tr>
        </tbody>
      </table>
    </div>

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <tbody>
          <tr>
            <td>**Function Call**</td>
            <td><code>JSON\_PRETTY('\{"A": "B", "C": \{"D": 5, "F": 7}}')</code></td>
          </tr>

          <tr>
            <td>**Return**</td>
            <td><pre><code>\{
            "A": "B",
            "C": \{
            "D": 5,
            "F": 7
            }
            ]</code></pre></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_QUERY (json, path [<return>])" id="json_query-json-path-<return>" defaultOpen>
    Returns the JSON object at the given `path` in `json`; null, if the path doesn't exist
    or contains a primitive (non-object) value

    An optional `return` clause can be added to the end of the path to specify the return type
    of the object found, as well as the error handling for the object lookup.  The format of the
    clause is:

    ```
    [<wrapper> WRAPPER] [<empty_hand> ON EMPTY] [<error hand> ON ERROR]
    ```

    <Info>
      Return clause is only available in SQL or in the native API via
      [/execute/sql](/content/api/rest/execute_sql_rest).
    </Info>

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Parameter</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>\<wrapper></code></td>
            <td>Whether the returned object(s) should be wrapped in an array before being returned Valid wrapping schemes include: <ul><li><code>WITHOUT \[ARRAY]</code> - no wrapper is applied *(default)*</li><li><code>WITH \[UNCONDITIONAL] \[ARRAY]</code> - return the object(s) in an array</li><li><code>WITH CONDITIONAL \[ARRAY]</code> - if returning a single object, don't wrap it; if returning multiple objects, wrap them in an array</li></ul></td>
          </tr>

          <tr>
            <td><code>\<empty hand></code></td>
            <td>The scheme to use for handling empty returned objects Valid schemes include: <ul><li><code>NULL</code> - return *null* *(default)*</li><li><code>ERROR</code> - throw an error</li><li><code>EMPTY ARRAY</code> - return an empty array</li><li><code>EMPTY OBJECT</code> - return an empty object</li></ul></td>
          </tr>

          <tr>
            <td><code>\<error hand></code></td>
            <td>The scheme to use for handling errors in looking up the object Valid schemes include: <ul><li><code>NULL</code> - return *null* *(default)*</li><li><code>ERROR</code> - throw an error</li><li><code>EMPTY ARRAY</code> - return an empty array</li><li><code>EMPTY OBJECT</code> - return an empty object</li></ul></td>
          </tr>
        </tbody>
      </table>
    </div>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_QUERY('\[1, 2]', '\$')</code></td>
            <td><code>\[1,2]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\[1, 2]', '\$.A')</code></td>
            <td>*null*</td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\{"A": \[2, 3]}', '\$.A')</code></td>
            <td><code>\[2,3]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\{"A": \{"B": 3, "D": 5}}', '\$\["A"]')</code></td>
            <td><code>\{"B":3,"D":5}</code></td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\{"A": \{"B": 3, "D": 5}}', '\$\["A"]\["D"]')</code></td>
            <td>*null*</td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\{"A": \{"B": 3, "D": \[5, 6]}}', '\$\["A"]\["D"]')</code></td>
            <td><code>\[5,6]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\{"A": \[]}', '\$.B'  EMPTY ARRAY ON EMPTY)</code></td>
            <td><code>\[]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\{"A": 0}', '\$.A'  EMPTY OBJECT ON ERROR)</code></td>
            <td><code>\{}</code></td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\{"A": 2, "C": 4}', '\$.\*')</code></td>
            <td>*null*</td>
          </tr>

          <tr>
            <td><code>JSON\_QUERY('\{"A": 2, "C": 4}', '\$.\*' WITH WRAPPER)</code></td>
            <td><code>\[2,4]</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_REPLACE(json, path, repl)" id="json_replace-json-path-repl" defaultOpen>
    Returns the given `json` with the value at the JSON path `path` replaced with the
    replacement value `repl`

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_REPLACE('\[1, 2]', '\$', '\[3, 4]')</code></td>
            <td><code>\[3,4]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_REPLACE('\[1, 2]', '\$.A', '"B"')</code></td>
            <td><code>\[1,2]</code></td>
          </tr>

          <tr>
            <td><code>JSON\_REPLACE('\{"A": \[2, 3]}', '\$.A', '\{"D": 5}')</code></td>
            <td><code>\{"A":\{"D":5}}</code></td>
          </tr>

          <tr>
            <td><code>JSON\_REPLACE('\{"A": \{"B": 3}}', '\$\["A"]', '"D"')</code></td>
            <td><code>\{"A":"D"}</code></td>
          </tr>

          <tr>
            <td><code>JSON\_REPLACE('\{"A": \{"B": \[3, 4]}}', '\$\["A"]\["B"]', 5)</code></td>
            <td><code>\{"A":\{"B":5}}</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_TYPE(expr)" id="json_type-expr" defaultOpen>
    Returns the JSON type of the given `expr`

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Expression Type</th>
            <th>JSON Type</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>BOOLEAN</code></td>
            <td><code>BOOLEAN</code></td>
          </tr>

          <tr>
            <td><ul><li><code>TINYINT</code></li><li><code>SMALLINT</code></li><li><code>INTEGER</code></li><li><code>BIGINT</code></li><li><code>UNSIGNED BIGINT</code></li></ul></td>
            <td><code>LONG</code></td>
          </tr>

          <tr>
            <td><ul><li><code>REAL</code></li><li><code>DOUBLE</code></li></ul></td>
            <td><code>DOUBLE</code></td>
          </tr>

          <tr>
            <td><ul><li><code>JSON</code></li><li><code>VARCHAR</code></li></ul></td>
            <td><ul><li><code>BOOLEAN</code> - if <code>true</code> or <code>false</code></li><li><code>LONG</code> - if an integer value</li><li><code>DOUBLE</code> - if a floating-point value</li><li><code>STRING</code> - if a double-quoted literal</li><li><code>OBJECT</code> - if a JSON map</li><li><code>ARRAY</code> - if a JSON array</li></ul></td>
          </tr>

          <tr>
            <td><code>ARRAY</code> *(any)*</td>
            <td><code>ARRAY</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="JSON_VALUE (json, path [return])" id="json_value-json-path-return" defaultOpen>
    Returns the JSON value at the given `path` in `json`; null, if the path doesn't exist
    or contains an object (non-primitive) value

    An optional `return` clause can be added to the end of the path to specify the return type
    of the value found, as well as the error handling for the value lookup.  The format of the
    clause is:

    ```
    [RETURNING <type>] [<empty_hand> ON EMPTY] [<error hand> ON ERROR]
    ```

    <Info>
      Return clause is only available in SQL or in the native API via
      [/execute/sql](/content/api/rest/execute_sql_rest).
    </Info>

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Parameter</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>\<type></code></td>
            <td>The JSON type of the value to return; if the value is not already of that type, it will be cast to that type, if possible Valid types include: <ul><li><code>BOOLEAN</code></li><li><code>LONG</code></li><li><code>DOUBLE</code></li><li><code>STRING</code></li></ul></td>
          </tr>

          <tr>
            <td><code>\<empty hand></code></td>
            <td>The scheme to use for handling empty returned values Valid schemes include: <ul><li><code>NULL</code> - return *null* *(default)*</li><li><code>ERROR</code> - throw an error</li><li><code>DEFAULT \<expr></code> - return the given expression <code>expr</code></li></ul></td>
          </tr>

          <tr>
            <td><code>\<error hand></code></td>
            <td>The scheme to use for handling errors in looking up the value Valid schemes include: <ul><li><code>NULL</code> - return *null* *(default)*</li><li><code>ERROR</code> - throw an error</li><li><code>DEFAULT \<expr></code> - return the given expression <code>expr</code></li></ul></td>
          </tr>
        </tbody>
      </table>
    </div>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>JSON\_VALUE('1', '\$')</code></td>
            <td><code>1</code></td>
          </tr>

          <tr>
            <td><code>JSON\_VALUE('\[1, 2]', '\$.A')</code></td>
            <td>*null*</td>
          </tr>

          <tr>
            <td><code>JSON\_VALUE('\["A", "B"]', '\$.1')</code></td>
            <td><code>B</code></td>
          </tr>

          <tr>
            <td><code>JSON\_VALUE('\{"A": \[2, 3]}', '\$\["A"]\["1"]')</code></td>
            <td><code>3</code></td>
          </tr>

          <tr>
            <td><code>JSON\_VALUE('\{"A": \{"B": 3, "D": 5}}', '\$\["A"]\["D"]')</code></td>
            <td><code>5</code></td>
          </tr>

          <tr>
            <td><code>JSON\_VALUE('\{"A": \{"B": 3, "D": \[5, 6]}}', '\$.A.D.1')</code></td>
            <td><code>6</code></td>
          </tr>

          <tr>
            <td><code>JSON\_VALUE('1', '\$' RETURNING DOUBLE)</code></td>
            <td><code>1.0</code></td>
          </tr>

          <tr>
            <td><code>JSON\_VALUE('\{"A": \[]}', '\$.B' DEFAULT '\<null>' ON EMPTY)</code></td>
            <td><code>\<null></code></td>
          </tr>

          <tr>
            <td><code>JSON\_VALUE('\{"A": \[]}', '\$.A' ERROR ON ERROR)</code></td>
            <td>*error returned*</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>
</AccordionGroup>

<a id="sql-json-functions-agg" />

### Aggregation Functions

The following functions can be used on [JSON](/content/concepts/json)
columns within [aggregations](/content/sql/query#sql-aggregation).

<AccordionGroup>
  <Accordion title="JSON_ARRAYAGG(expr)" id="json_arrayagg-expr" defaultOpen>
    Combines column values within a group into a single JSON array of those values.

    See [examples](/content/concepts/json#json-func-agg-ex-agg).
  </Accordion>

  <Accordion title="JSON_ARRAYAGG_DISTINCT(expr)" id="json_arrayagg_distinct-expr" defaultOpen>
    Combines column values within a group into a single JSON array of those values,
    removing any duplicates.

    See [examples](/content/concepts/json#json-func-agg-ex-agg-dist).
  </Accordion>

  <Accordion title="JSON_COLLECT_SET(expr)" id="json_collect_set-expr" defaultOpen>
    Alias for `JSON_ARRAYAGG_DISTINCT`.
  </Accordion>
</AccordionGroup>

<a id="sql-math-functions" />

## Math Functions

### Scalar Functions

<AccordionGroup>
  <Accordion title="ABS(expr)" id="abs-expr" defaultOpen>
    Calculates the absolute value of `expr`
  </Accordion>

  <Accordion title="ACOS(expr)" id="acos-expr" defaultOpen>
    Returns the inverse cosine (arccosine) of `expr` as a *double*
  </Accordion>

  <Accordion title="ACOSF(expr)" id="acosf-expr" defaultOpen>
    Returns the inverse cosine (arccosine) of `expr` as a *float*
  </Accordion>

  <Accordion title="ACOSH(expr)" id="acosh-expr" defaultOpen>
    Returns the inverse hyperbolic cosine of `expr` as a *double*
  </Accordion>

  <Accordion title="ACOSHF(expr)" id="acoshf-expr" defaultOpen>
    Returns the inverse hyperbolic cosine of `expr` as a *float*
  </Accordion>

  <Accordion title="ASIN(expr)" id="asin-expr" defaultOpen>
    Returns the inverse sine (arcsine) of `expr` as a *double*
  </Accordion>

  <Accordion title="ASINF(expr)" id="asinf-expr" defaultOpen>
    Returns the inverse sine (arcsine) of `expr` as a *float*
  </Accordion>

  <Accordion title="ASINH(expr)" id="asinh-expr" defaultOpen>
    Returns the inverse hyperbolic sine of `expr` as a *double*
  </Accordion>

  <Accordion title="ASINHF(expr)" id="asinhf-expr" defaultOpen>
    Returns the inverse hyperbolic sine of `expr` as a *float*
  </Accordion>

  <Accordion title="ATAN(expr)" id="atan-expr" defaultOpen>
    Returns the inverse tangent (arctangent) of `expr` as a *double*
  </Accordion>

  <Accordion title="ATANF(expr)" id="atanf-expr" defaultOpen>
    Returns the inverse tangent (arctangent) of `expr` as a *float*
  </Accordion>

  <Accordion title="ATANH(expr)" id="atanh-expr" defaultOpen>
    Returns the inverse hyperbolic tangent of `expr` as a *double*
  </Accordion>

  <Accordion title="ATANHF(expr)" id="atanhf-expr" defaultOpen>
    Returns the inverse hyperbolic tangent of `expr` as a *float*
  </Accordion>

  <Accordion title="ATAN2(x, y)" id="atan2-x-y" defaultOpen>
    Returns the inverse tangent (arctangent) using two arguments as a *double*
  </Accordion>

  <Accordion title="ATAN2F(x, y)" id="atan2f-x-y" defaultOpen>
    Returns the inverse tangent (arctangent) using two arguments as a *float*
  </Accordion>

  <Accordion title="ATN2(x, y)" id="atn2-x-y" defaultOpen>
    Alias for `ATAN2`
  </Accordion>

  <Accordion title="ATN2F(x, y)" id="atn2f-x-y" defaultOpen>
    Alias for `ATAN2F`
  </Accordion>

  <Accordion title="CBRT(expr)" id="cbrt-expr" defaultOpen>
    Returns the cube root of `expr` as a *double*
  </Accordion>

  <Accordion title="CBRTF(expr)" id="cbrtf-expr" defaultOpen>
    Returns the cube root of `expr` as a *float*
  </Accordion>

  <Accordion title="CEIL(expr)" id="ceil-expr" defaultOpen>
    Alias for `CEILING`
  </Accordion>

  <Accordion title="CEILING(expr)" id="ceiling-expr" defaultOpen>
    Rounds `expr` up to the next highest integer
  </Accordion>

  <Accordion title="COS(expr)" id="cos-expr" defaultOpen>
    Returns the cosine of `expr` as a *double*
  </Accordion>

  <Accordion title="COSF(expr)" id="cosf-expr" defaultOpen>
    Returns the cosine of `expr` as a *float*
  </Accordion>

  <Accordion title="COSH(expr)" id="cosh-expr" defaultOpen>
    Returns the hyperbolic cosine of `expr` as a *double*
  </Accordion>

  <Accordion title="COSHF(expr)" id="coshf-expr" defaultOpen>
    Returns the hyperbolic cosine of `expr` as a *float*
  </Accordion>

  <Accordion title="COT(expr)" id="cot-expr" defaultOpen>
    Returns the cotangent of `expr` as a *double*
  </Accordion>

  <Accordion title="COTF(expr)" id="cotf-expr" defaultOpen>
    Returns the cotangent of `expr` as a *float*
  </Accordion>

  <Accordion title="DEGREES(expr)" id="degrees-expr" defaultOpen>
    Returns the conversion of `expr` (in radians) to degrees as a *double*
  </Accordion>

  <Accordion title="DEGREESF(expr)" id="degreesf-expr" defaultOpen>
    Returns the conversion of `expr` (in radians) to degrees as a *float*
  </Accordion>

  <Accordion title="DIVZ(a, b, c)" id="divz-a-b-c" defaultOpen>
    Returns the quotient `a / b` unless `b == 0`, in which case it returns `c`
  </Accordion>

  <Accordion title="EXP(expr)" id="exp-expr" defaultOpen>
    Returns *e* to the power of `expr` as a *double*
  </Accordion>

  <Accordion title="EXPF(expr)" id="expf-expr" defaultOpen>
    Returns *e* to the power of `expr` as a *float*
  </Accordion>

  <Accordion title="FLOOR(expr)" id="floor-expr" defaultOpen>
    Rounds `expr` down to the next lowest integer
  </Accordion>

  <Accordion title="GREATER(expr_a, expr_b)" id="greater-expr_a-expr_b" defaultOpen>
    Returns whichever of `expr_a` and `expr_b` has the larger value, based on typed
    comparison
  </Accordion>

  <Accordion title="HYPOT(x, y)" id="hypot-x-y" defaultOpen>
    Returns the hypotenuse of `x` and `y` as a *double*
  </Accordion>

  <Accordion title="HYPOTF(x, y)" id="hypotf-x-y" defaultOpen>
    Returns the hypotenuse of `x` and `y` as a *float*
  </Accordion>

  <Accordion title="IFERROR(expr, val)" id="iferror-expr-val" defaultOpen>
    Alias for `IF_ERROR(expr, val)`
  </Accordion>

  <Accordion title="IFINF(expr, val)" id="ifinf-expr-val" defaultOpen>
    Alias for `IF_INF(expr, val)`
  </Accordion>

  <Accordion title="IFINFINITY(expr, val)" id="ifinfinity-expr-val" defaultOpen>
    Alias for `IF_INF(expr, val)`
  </Accordion>

  <Accordion title="IFNAN(expr, val)" id="ifnan-expr-val" defaultOpen>
    Alias for `IF_NAN(expr, val)`
  </Accordion>

  <Accordion title="IF_ERROR(expr, val)" id="if_error-expr-val" defaultOpen>
    Evaluates the given *double* or *float* `expr`, and if it resolves to infinity or
    `NaN`, return `val`

    <Tip>
      Conceptually, this function is the same as
      `IF_INF(IF_NAN(expr, val), val)`
    </Tip>

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>IF\_ERROR((double(10)/0), 1)</code></td>
            <td><code>1.0</code></td>
          </tr>

          <tr>
            <td><code>IF\_ERROR(log(-1), 1)</code></td>
            <td><code>1.0</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="IF_INF(expr, val)" id="if_inf-expr-val" defaultOpen>
    Evaluates the given *double* or *float* `expr`, and if it resolves to infinity,
    return `val`

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>IF\_INF((double(10)/0), 999)</code></td>
            <td><code>999.0</code></td>
          </tr>

          <tr>
            <td><code>IF\_INF(log(-1), 999)</code></td>
            <td><code>NaN</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="IF_INFINITY(expr, val)" id="if_infinity-expr-val" defaultOpen>
    Alias for `IF_INF(expr, val)`
  </Accordion>

  <Accordion title="IF_NAN(expr, val)" id="if_nan-expr-val" defaultOpen>
    Evaluates the given *double* or *float* `expr`, and if it resolves to `NaN`,
    return `val`

    Example:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>IF\_NAN((double(10)/0), -1)</code></td>
            <td><code>Infinity</code></td>
          </tr>

          <tr>
            <td><code>IF\_NAN(log(-1), -1)</code></td>
            <td><code>-1.0</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="ISINFINITY(expr)" id="isinfinity-expr" defaultOpen>
    Returns `1` (true) if `expr` is infinity by IEEE standard; otherwise, returns
    `0` (false)
  </Accordion>

  <Accordion title="IS_INFINITY(expr)" id="is_infinity-expr" defaultOpen>
    Alias for `ISINFINITY`
  </Accordion>

  <Accordion title="ISNAN(expr)" id="isnan-expr" defaultOpen>
    Returns `1` (true) if `expr` is not a number by IEEE standard; otherwise, returns
    `0` (false)
  </Accordion>

  <Accordion title="IS_NAN(expr)" id="is_nan-expr" defaultOpen>
    Alias for `ISNAN`
  </Accordion>

  <Accordion title="ISNUMERIC(expr)" id="isnumeric-expr" defaultOpen>
    Returns `1` (true) if `expr` is a number by IEEE standard; otherwise, returns
    `0` (false)
  </Accordion>

  <Accordion title="IS_NUMERIC(expr)" id="is_numeric-expr" defaultOpen>
    Alias for `ISNUMERIC`
  </Accordion>

  <Accordion title="LDEXP(x, exp)" id="ldexp-x-exp" defaultOpen>
    Returns the value of `x` \* 2<sup>exp</sup> as a *double*
  </Accordion>

  <Accordion title="LDEXPF(x, exp)" id="ldexpf-x-exp" defaultOpen>
    Returns the value of `x` \* 2<sup>exp</sup> as a *float*
  </Accordion>

  <Accordion title="LESSER(expr_a, expr_b)" id="lesser-expr_a-expr_b" defaultOpen>
    Returns whichever of `expr_a` and `expr_b` has the smaller value, based on typed
    comparison
  </Accordion>

  <Accordion title="LN(expr)" id="ln-expr" defaultOpen>
    Returns the natural logarithm of `expr` as a *double*
  </Accordion>

  <Accordion title="LNF(expr)" id="lnf-expr" defaultOpen>
    Returns the natural logarithm of `expr` as a *float*
  </Accordion>

  <Accordion title="LOG(expr)" id="log-expr" defaultOpen>
    Alias for `LN`
  </Accordion>

  <Accordion title="LOG10(expr)" id="log10-expr" defaultOpen>
    Returns the *base-10* logarithm of `expr` as a *double*
  </Accordion>

  <Accordion title="LOG10F(expr)" id="log10f-expr" defaultOpen>
    Returns the *base-10* logarithm of `expr` as a *float*
  </Accordion>

  <Accordion title="LOG1P(expr)" id="log1p-expr" defaultOpen>
    Returns the natural logarithm of one plus `expr` as a *double*
  </Accordion>

  <Accordion title="LOG1PF(expr)" id="log1pf-expr" defaultOpen>
    Returns the natural logarithm of one plus `expr` as a *float*
  </Accordion>

  <Accordion title="LOG2(expr)" id="log2-expr" defaultOpen>
    Returns the binary (*base-2*) logarithm of `expr` as a *double*
  </Accordion>

  <Accordion title="LOG2F(expr)" id="log2f-expr" defaultOpen>
    Returns the binary (*base-2*) logarithm of `expr` as a *float*
  </Accordion>

  <Accordion title="LOGF(expr)" id="logf-expr" defaultOpen>
    Alias for `LNF`
  </Accordion>

  <Accordion title="MAX_CONSECUTIVE_BITS(expr)" id="max_consecutive_bits-expr" defaultOpen>
    Calculates the length of the longest series of consecutive `1` bits in the integer
    `expr`
  </Accordion>

  <Accordion title="MOD(dividend, divisor)" id="mod-dividend-divisor" defaultOpen>
    Calculates the remainder after integer division of `dividend` by `divisor`
  </Accordion>

  <Accordion title="NEXT_AFTER(expr[, target])" id="next_after-expr-target" defaultOpen>
    Returns the next representable floating-point value adjacent to
    `expr` in the direction of `target`, incrementing `expr`
    if `target` is greater, decrementing if lesser.  The default
    value of `target` is `MAX_DOUBLE` (always increments when
    omitted).  The return type matches the input (*float* or *double*).
  </Accordion>

  <Accordion title="NEXT_BEFORE(expr)" id="next_before-expr" defaultOpen>
    Returns the next representable floating-point value less than
    `expr`.  The return type matches the input (*float* or *double*).
  </Accordion>

  <Accordion title="PI()" id="pi" defaultOpen>
    Returns the value of *pi*
  </Accordion>

  <Accordion title="POW(base, exponent)" id="pow-base-exponent" defaultOpen>
    Alias for `POWER`
  </Accordion>

  <Accordion title="POWF(base, exponent)" id="powf-base-exponent" defaultOpen>
    Alias for `POWERF`
  </Accordion>

  <Accordion title="POWER(base, exponent)" id="power-base-exponent" defaultOpen>
    Returns `base` raised to the power of `exponent` as a *double*
  </Accordion>

  <Accordion title="POWERF(base, exponent)" id="powerf-base-exponent" defaultOpen>
    Returns `base` raised to the power of `exponent` as a *float*
  </Accordion>

  <Accordion title="RADIANS(expr)" id="radians-expr" defaultOpen>
    Returns the conversion of `expr` (in degrees) to radians as a *double*
  </Accordion>

  <Accordion title="RADIANSF(expr)" id="radiansf-expr" defaultOpen>
    Returns the conversion of `expr` (in degrees) to radians as a *float*
  </Accordion>

  <Accordion title="RAND([seed])" id="rand-seed" defaultOpen>
    Returns a random floating-point value, with an optional `seed`
  </Accordion>

  <Accordion title="REGR_VALX(y, x)" id="regr_valx-y-x" defaultOpen>
    Returns NULL if `y` is NULL; otherwise, returns `x`
  </Accordion>

  <Accordion title="REGR_VALY(y, x)" id="regr_valy-y-x" defaultOpen>
    Returns NULL if `x` is NULL; otherwise, returns `y`
  </Accordion>

  <Accordion title="ROUND(expr[, scale])" id="round-expr-scale" defaultOpen>
    Rounds `expr` to the nearest decimal number with `scale`
    decimal places when `scale` is a positive number; rounds to
    the nearest number such that the result has `-(scale)` zeros
    to the left of the decimal point when `scale` is negative; use
    `scale` of `0` to round to the nearest integer.

    The default value of `scale` is `0`.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>ROUND(12345.678)</code></td>
            <td><code>12346</code></td>
          </tr>

          <tr>
            <td><code>ROUND(12345.678, 2)</code></td>
            <td><code>12345.68</code></td>
          </tr>

          <tr>
            <td><code>ROUND(12345.678, 0)</code></td>
            <td><code>12346</code></td>
          </tr>

          <tr>
            <td><code>ROUND(12345.678, -2)</code></td>
            <td><code>12300</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="SIGN(expr)" id="sign-expr" defaultOpen>
    Determines whether a number is positive, negative, or zero;
    returns one of the following three values:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Expression Value</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td>*positive*</td>
            <td><code>1</code></td>
          </tr>

          <tr>
            <td>*zero*</td>
            <td><code>0</code></td>
          </tr>

          <tr>
            <td>*negative*</td>
            <td><code>-1</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="SIN(expr)" id="sin-expr" defaultOpen>
    Returns the sine of `expr` as a *double*
  </Accordion>

  <Accordion title="SINF(expr)" id="sinf-expr" defaultOpen>
    Returns the sine of `expr` as a *float*
  </Accordion>

  <Accordion title="SINH(expr)" id="sinh-expr" defaultOpen>
    Returns the hyperbolic sine of `expr` as a *double*
  </Accordion>

  <Accordion title="SINHF(expr)" id="sinhf-expr" defaultOpen>
    Returns the hyperbolic sine of `expr` as a *float*
  </Accordion>

  <Accordion title="SQRT(expr)" id="sqrt-expr" defaultOpen>
    Returns the square root of `expr` as a *double*
  </Accordion>

  <Accordion title="SQRTF(expr)" id="sqrtf-expr" defaultOpen>
    Returns the square root of `expr` as a *float*
  </Accordion>

  <Accordion title="TAN(expr)" id="tan-expr" defaultOpen>
    Returns the tangent of `expr` as a *double*
  </Accordion>

  <Accordion title="TANF(expr)" id="tanf-expr" defaultOpen>
    Returns the tangent of `expr` as a *float*
  </Accordion>

  <Accordion title="TANH(expr)" id="tanh-expr" defaultOpen>
    Returns the hyperbolic tangent of `expr` as a *double*
  </Accordion>

  <Accordion title="TANHF(expr)" id="tanhf-expr" defaultOpen>
    Returns the hyperbolic tangent of `expr` as a *float*
  </Accordion>

  <Accordion title="TRUNCATE(expr[, scale])" id="truncate-expr-scale" defaultOpen>
    Rounds `expr` down to the nearest decimal number with
    `scale` decimal places when `scale` is a positive number;
    rounds down to the nearest number such that the result has
    `-(scale)` zeros to the left of the decimal point when
    `scale` is negative; use `scale` of `0` to round down to
    the nearest integer.

    The default value of `scale` is `0`.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>TRUNCATE(12345.678)</code></td>
            <td><code>12345</code></td>
          </tr>

          <tr>
            <td><code>TRUNCATE(12345.678, 2)</code></td>
            <td><code>12345.67</code></td>
          </tr>

          <tr>
            <td><code>TRUNCATE(12345.678, 0)</code></td>
            <td><code>12345</code></td>
          </tr>

          <tr>
            <td><code>TRUNCATE(12345.678, -2)</code></td>
            <td><code>12300</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="WIDTH_BUCKET(expr, min, max, count)" id="width_bucket-expr-min-max-count" defaultOpen>
    Defines a set of `count` equal intervals (buckets) within the range of `min` &
    `max`, and puts the value of `expr` into one of those buckets, where the value is
    greater than or equal to the minimum value of the bucket and less than the maximum
    value of the bucket.  Returns the 1-based number of the bucket into which the value
    of `expr` fell.  For values smaller than `min`, `0` is returned; for values
    greater than or equal to `max`, `count + 1` is returned.  Examples:

    In the following examples, a set of *5* equal buckets are defined between *0* and
    *10* (*0-2*, *2-4*, *4-6*, *6-8*, & *8-10*), and various values are bucketed using
    that set.

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>WIDTH\_BUCKET(-1, 0, 10, 5)</code></td>
            <td><code>0</code></td>
          </tr>

          <tr>
            <td><code>WIDTH\_BUCKET(0, 0, 10, 5)</code></td>
            <td><code>1</code></td>
          </tr>

          <tr>
            <td><code>WIDTH\_BUCKET(5, 0, 10, 5)</code></td>
            <td><code>3</code></td>
          </tr>

          <tr>
            <td><code>WIDTH\_BUCKET(10, 0, 10, 5)</code></td>
            <td><code>6</code></td>
          </tr>

          <tr>
            <td><code>WIDTH\_BUCKET(11, 0, 10, 5)</code></td>
            <td><code>6</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>
</AccordionGroup>

<a id="sql-math-functions-agg" />

### Aggregate Functions

<AccordionGroup>
  <Accordion title="APPROX_COUNT_DISTINCT(expr)" id="approx_count_distinct-expr" defaultOpen>
    The approximate number of distinct values of `expr`; this is faster to calculate than `COUNT_DISTINCT` but is only an approximation
  </Accordion>

  <Accordion title="APPROX_MEDIAN(expr)" id="approx_median-expr" defaultOpen>
    The approximate median of `expr`; the result should be within about *2%* of the true median value. This is equivalent to issuing
    `APPROX_PERCENTILE(expr, 50)`.
  </Accordion>

  <Accordion title="APPROX_PERCENTILE(expr, p)" id="approx_percentile-expr-p" defaultOpen>
    The approximate *pth* percentile of `expr`; `p` should be a value between *0.0* and *100.0*. `APPROX_PERCENTILE(expr, 50)` will return
    the approximate median of `expr`.
  </Accordion>

  <Accordion title="AVG(expr)" id="avg-expr-2" defaultOpen>
    Average of the values of `expr`
  </Accordion>

  <Accordion title="CORR(expr1, expr2)" id="corr-expr1-expr2" defaultOpen>
    Correlation coefficient of the values of `expr1` and `expr2`
  </Accordion>

  <Accordion title="CORRELATION(expr1, expr2)" id="correlation-expr1-expr2" defaultOpen>
    Alias for `CORR`
  </Accordion>

  <Accordion title="CORRCOEF(expr1, expr2)" id="corrcoef-expr1-expr2" defaultOpen>
    Alias for `CORR`
  </Accordion>

  <Accordion title="COUNT(expr)" id="count-expr-2" defaultOpen>
    Count of non-null values of `expr`; use `*` to count all values within an aggregation group or over an entire table
  </Accordion>

  <Accordion title="COUNT_DISTINCT(expr)" id="count_distinct-expr" defaultOpen>
    Count of the distinct values of `expr`
  </Accordion>

  <Accordion title="COV(expr1, expr2)" id="cov-expr1-expr2" defaultOpen>
    Alias for `COVAR_POP`
  </Accordion>

  <Accordion title="COVAR(expr1, expr2)" id="covar-expr1-expr2" defaultOpen>
    Alias for `COVAR_POP`
  </Accordion>

  <Accordion title="COVARIANCE(expr1, expr2)" id="covariance-expr1-expr2" defaultOpen>
    Alias for `COVAR_POP`
  </Accordion>

  <Accordion title="COVAR_POP(expr1, expr2)" id="covar_pop-expr1-expr2" defaultOpen>
    Population covariance of the values of `expr1` and `expr2`
  </Accordion>

  <Accordion title="COVAR_SAMP(expr1, expr2)" id="covar_samp-expr1-expr2" defaultOpen>
    Sample covariance of the values of `expr1` and `expr2`
  </Accordion>

  <Accordion title="KURT(expr)" id="kurt-expr" defaultOpen>
    Alias for `KURTOSIS_POP`
  </Accordion>

  <Accordion title="KURTOSIS(expr)" id="kurtosis-expr" defaultOpen>
    Alias for `KURTOSIS_POP`
  </Accordion>

  <Accordion title="KURTOSIS_POP(expr)" id="kurtosis_pop-expr" defaultOpen>
    Population kurtosis of the values of `expr`
  </Accordion>

  <Accordion title="KURTOSIS_SAMP(expr)" id="kurtosis_samp-expr" defaultOpen>
    Sample kurtosis of the values of `expr`
  </Accordion>

  <Accordion title="KURT_POP(expr)" id="kurt_pop-expr" defaultOpen>
    Alias for `KURTOSIS_POP`
  </Accordion>

  <Accordion title="KURT_SAMP(expr)" id="kurt_samp-expr" defaultOpen>
    Alias for `KURTOSIS_SAMP`
  </Accordion>

  <Accordion title="MAX(expr)" id="max-expr-2" defaultOpen>
    Maximum of the values of `expr`
  </Accordion>

  <Accordion title="MEAN(expr)" id="mean-expr-2" defaultOpen>
    Alias for `AVG`
  </Accordion>

  <Accordion title="MIN(expr)" id="min-expr-2" defaultOpen>
    Minimum of the values of `expr`
  </Accordion>

  <Accordion title="PRODUCT(expr)" id="product-expr-2" defaultOpen>
    Product of the values of `expr`
  </Accordion>

  <Accordion title="REGR_AVGX(y, x)" id="regr_avgx-y-x" defaultOpen>
    Average of the independent variable (`SUM(x)/N`) of the line determined by computing a least-squares-fit linear regression over the given (X, Y)
    pairs
  </Accordion>

  <Accordion title="REGR_AVGY(y, x)" id="regr_avgy-y-x" defaultOpen>
    Average of the dependent variable (`SUM(y)/N`) of the line determined by computing a least-squares-fit linear regression over the given (X, Y)
    pairs
  </Accordion>

  <Accordion title="REGR_COUNT(y, x)" id="regr_count-y-x" defaultOpen>
    Number of input rows used in computing a linear regression, where both expressions are non-null
  </Accordion>

  <Accordion title="REGR_INTERCEPT(y, x)" id="regr_intercept-y-x" defaultOpen>
    Y-intercept of the line determined by computing a least-squares-fit linear regression over the given (X, Y) pairs
  </Accordion>

  <Accordion title="REGR_R2(y, x)" id="regr_r2-y-x" defaultOpen>
    Square of the correlation coefficient, marking how well the least-squares-fit linear regression fit the data set
  </Accordion>

  <Accordion title="REGR_SLOPE(y, x)" id="regr_slope-y-x" defaultOpen>
    Slope of the line determined by computing a least-squares-fit linear regression over the given (X, Y) pairs
  </Accordion>

  <Accordion title="REGR_SXX(y, x)" id="regr_sxx-y-x" defaultOpen>
    "Sum of squares" of the independent variable (`SUM(x^2) - SUM(x)^2/N`) of the line determined by computing a least-squares-fit linear regression
    over the given (X, Y) pairs
  </Accordion>

  <Accordion title="REGR_SXY(y, x)" id="regr_sxy-y-x" defaultOpen>
    "Sum of Products" of independent variable times dependent variable (`SUM(x * y) - SUM(x) * SUM(y)/N`) of the line determined by computing a
    least-squares-fit linear regression over the given (X, Y) pairs
  </Accordion>

  <Accordion title="REGR_SYY(y, x)" id="regr_syy-y-x" defaultOpen>
    "Sum of squares" of the dependent variable (`SUM(y^2) - SUM(y)^2/N`) of the line determined by computing a least-squares-fit linear regression
    over the given (X, Y) pairs
  </Accordion>

  <Accordion title="SKEW(expr)" id="skew-expr" defaultOpen>
    Alias for `SKEWNESS_POP`
  </Accordion>

  <Accordion title="SKEWNESS(expr)" id="skewness-expr" defaultOpen>
    Alias for `SKEWNESS_POP`
  </Accordion>

  <Accordion title="SKEWNESS_POP(expr)" id="skewness_pop-expr" defaultOpen>
    Population skew of the values of `expr`
  </Accordion>

  <Accordion title="SKEWNESS_SAMP(expr)" id="skewness_samp-expr" defaultOpen>
    Sample skew of the values of `expr`
  </Accordion>

  <Accordion title="SKEW_POP(expr)" id="skew_pop-expr" defaultOpen>
    Alias for `SKEWNESS_POP`
  </Accordion>

  <Accordion title="SKEW_SAMP(expr)" id="skew_samp-expr" defaultOpen>
    Alias for `SKEWNESS_SAMP`
  </Accordion>

  <Accordion title="STDDEV(expr)" id="stddev-expr-2" defaultOpen>
    Population standard deviation over values of `expr` (i.e. the denominator is *N*)
  </Accordion>

  <Accordion title="STDDEV_POP(expr)" id="stddev_pop-expr-2" defaultOpen>
    Population standard deviation over values of `expr` (i.e. the denominator is *N*)
  </Accordion>

  <Accordion title="STDDEV_SAMP(expr)" id="stddev_samp-expr-2" defaultOpen>
    Sample standard deviation over values of `expr` (i.e. the denominator is *N-1*)
  </Accordion>

  <Accordion title="SUM(expr)" id="sum-expr-2" defaultOpen>
    Sum of the values of `expr`
  </Accordion>

  <Accordion title="VAR(expr)" id="var-expr-2" defaultOpen>
    Population variance over values of `expr` (i.e. the denominator is *N*)
  </Accordion>

  <Accordion title="VAR_POP(expr)" id="var_pop-expr-2" defaultOpen>
    Population variance over values of `expr` (i.e. the denominator is *N*)
  </Accordion>

  <Accordion title="VAR_SAMP(expr)" id="var_samp-expr-2" defaultOpen>
    Sample variance over values of `expr` (i.e. the denominator is *N-1*)
  </Accordion>

  <Accordion title="VARIANCE(expr)" id="variance-expr" defaultOpen>
    Alias for `VAR`
  </Accordion>

  <Accordion title="VARIANCE_POP(expr)" id="variance_pop-expr" defaultOpen>
    Alias for `VAR_POP`
  </Accordion>

  <Accordion title="VARIANCE_SAMP(expr)" id="variance_samp-expr" defaultOpen>
    Alias for `VAR_SAMP`
  </Accordion>
</AccordionGroup>

<a id="sql-null-functions" />

## Null Functions

Some of the following null functions require parameters to be of convertible
data types.  Note that *limited-width* (charN) & *unlimited-width* (non-charN)
[string types](/content/concepts/types#types-chart) are not convertible.

<AccordionGroup>
  <Accordion title="COALESCE(expr_a, ..., expr_N)" id="coalesce-expr_a-expr_n" defaultOpen>
    Returns the value of the first expression that is
    not *null* starting with `expr_a` and ending
    with `expr_N`.  If all are *null*, then *null*
    is returned.  All expressions should be of the
    same or convertible data type.
  </Accordion>

  <Accordion title="IFNULL(expr_a, expr_b)" id="ifnull-expr_a-expr_b" defaultOpen>
    Returns `expr_a` if it is not *null*; otherwise,
    returns `expr_b`.  Both should be of the same or
    convertible data type. See
    [Short-Circuiting](/content/concepts/expressions#short-circuiting) for error-checking
    details.
  </Accordion>

  <Accordion title="IS_NULL(expr)" id="is_null-expr" defaultOpen>
    Returns `1` if `expr` is *null*; otherwise,
    returns `0`
  </Accordion>

  <Accordion title="ISNULL(expr)" id="isnull-expr" defaultOpen>
    Alias for `IS_NULL(expr)`
  </Accordion>

  <Accordion title="NULLIF(expr_a, expr_b)" id="nullif-expr_a-expr_b" defaultOpen>
    Returns *null* if `expr_a` equals `expr_b`;
    otherwise, returns the value of `expr_a`; both
    expressions should be of the same or convertible
    data type.
  </Accordion>

  <Accordion title="NVL(expr_a, expr_b)" id="nvl-expr_a-expr_b" defaultOpen>
    Alias for `IFNULL`
  </Accordion>

  <Accordion title="NVL2(expr, value_if_not_null, value_if_null)" id="nvl2-expr-value_if_not_null-value_if_null" defaultOpen>
    Evaluates `expr`: if not *null*, returns
    `value_if_not_null`; if *null*, returns
    `value_if_null`.  Both `value_if_not_null` &
    `value_if_null` should be of the same data type
    as `expr` or implicitly convertible; see
    [Short-Circuiting](/content/concepts/expressions#short-circuiting) for error-checking
    details.
  </Accordion>

  <Accordion title="REMOVE_NULLABLE(expr)" id="remove_nullable-expr" defaultOpen>
    Alias for `ZEROIFNULL`
  </Accordion>

  <Accordion title="ZEROIFNULL(expr)" id="zeroifnull-expr" defaultOpen>
    Replaces *null* values with appropriate values
    based on the column type (e.g., `0` if numeric
    column, an empty string if *charN* column, etc.).
    Also removes the `nullable`
    [column property](/content/concepts/types) if used
    to calculate a derived column.
  </Accordion>
</AccordionGroup>

<a id="sql-dist-functions" />

## Record Distribution Functions

Record distribution functions provide a means to locate any database record
within the memory processing hierarchy; and through aggregating the results,
determine the distribution of records across the cluster.

<AccordionGroup>
  <Accordion title="KI_CHUNK()" id="ki_chunk" defaultOpen>
    Returns the index of the chunk within the rank/TOM containing this record.
    This value may change as data is added or deleted from a table.
  </Accordion>

  <Accordion title="KI_CHUNK_ID()" id="ki_chunk_id" defaultOpen>
    Returns the ID of the chunk within the rank/TOM containing this record.
    This value should remain the same even after system restarts.
  </Accordion>

  <Accordion title="KI_CHUNK_MAX(col)" id="ki_chunk_max-col" defaultOpen>
    Returns the maximum value for the specified column in its chunk.
    If the data has changed, this value may be higher than any actual values.
  </Accordion>

  <Accordion title="KI_CHUNK_MIN(col)" id="ki_chunk_min-col" defaultOpen>
    Returns the minimum value for the specified column in its chunk.
    If the data has changed, this value may be lower than any actual values.
  </Accordion>

  <Accordion title="KI_CHUNK_OFFSET()" id="ki_chunk_offset" defaultOpen>
    Returns the index of the record within the chunk.
  </Accordion>

  <Accordion title="KI_PARTITION()" id="ki_partition" defaultOpen>
    Returns the index of the partition within the rank/TOM containing this record, for
    [partitioned](/content/concepts/tables#partitioning) tables.
  </Accordion>

  <Accordion title="KI_RANK()" id="ki_rank" defaultOpen>
    Returns the index of the rank containing this record.
  </Accordion>

  <Accordion title="KI_TOM()" id="ki_tom" defaultOpen>
    Returns the index of the TOM within the rank containing this record.
  </Accordion>
</AccordionGroup>

For example, the following query can be used to determine the distribution of
records of the `example.stocks` table across the nodes of the cluster.

<CodeGroup>
  ```sql Non-Partitioned Distribution theme={null}
  SELECT
  	KI_RANK() AS "Rank",
  	COUNT(*) AS "TotalRecords"
  FROM example.stocks
  GROUP BY 1
  ORDER BY 1
  ```

  ```sql Partitioned Distribution theme={null}
  SELECT
  	KI_RANK() AS "Rank",
  	KI_PARTITION() AS "Partition",
  	COUNT(*) AS "TotalRecords"
  FROM example.stocks
  GROUP BY 1, 2
  ORDER BY 1, 2
  ```

  ```sql Multi-TOM Distribution theme={null}
  SELECT
  	KI_RANK() AS "Rank",
  	KI_TOM() AS "TOM",
  	COUNT(*) AS "TotalRecords"
  FROM example.stocks
  GROUP BY 1, 2
  ORDER BY 1, 2
  ```

  ```sql Chunk-Level Distribution theme={null}
  SELECT
  	KI_RANK() AS "Rank",
  	KI_CHUNK() AS "Chunk",
  	COUNT(*) AS "TotalRecords"
  FROM example.stocks
  GROUP BY 1, 2
  ORDER BY 1, 2
  ```
</CodeGroup>

For partitioned tables, `KI_PARTITION()` can be added to the query to also
the distribution across partitions, and for clusters with more than 1 TOM per
rank (1 TOM/rank is the default), `KI_TOM()` can be added.  To see chunk-level
distribution, use `KI_CHUNK()`.

<a id="sql-string-functions" />

## String Functions

There are four different types of string functions:

* [Scalar Functions](/content/sql/query#sql-string-functions-scalar)
* [Aggregation Functions](/content/sql/query#sql-string-functions-agg)
* [LIKE / ILIKE](/content/sql/query#sql-string-functions-like)
* [FILTER\_BY\_STRING](/content/sql/query#sql-string-functions-fts)

<Note>
  String columns are stored as byte arrays, but allow multi-byte
  characters, as they are UTF-8 encoded.  Some functions may behave in
  unexpected ways when given multi-byte input.
</Note>

<a id="sql-string-functions-charn" />

<a id="sql-string-functions-scalar" />

### Scalar Functions

<AccordionGroup>
  <Accordion title="ASCII(expr)" id="ascii-expr" defaultOpen>
    Returns the ASCII code for the first byte in `expr`
  </Accordion>

  <Accordion title="BIN(expr[, minimum_digits])" id="bin-expr-minimum_digits" defaultOpen>
    Convert the value represented by `expr` into a binary string
    representation.  Use optional `minimum_digits` to add leading 0s
    when needed; defaults to 1.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>BIN(42)</code></td>
            <td><code>'101010'</code></td>
          </tr>

          <tr>
            <td><code>BIN(42, 8)</code></td>
            <td><code>'00101010'</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="CHAR(expr)" id="char-expr-2" defaultOpen>
    The character represented by the standard ASCII code `expr` in the
    range \[ `0` - `127` ]
  </Accordion>

  <Accordion title="CONCAT(expr_a, expr_b)" id="concat-expr_a-expr_b" defaultOpen>
    Performs a string concatenation of `expr_a` & `expr_b`; use nested
    `CONCAT` calls to concatenate more than two strings

    <Info>
      The resulting field size of any `CONCAT` will be a
      `VARCHAR(N)` field big enough to hold the concatenated
      fields, e.g., concatenating a `VARCHAR(32)` column and a
      `VARCHAR(64)` column will result in a `VARCHAR(128)`
      column.  Columns of type `VARCHAR(256)` used with
      `CONCAT` will result in a `VARCHAR(256)` column,
      truncated at 256 characters.
    </Info>

    <Tip>
      The `||` operator can be used in place of `CONCAT` to
      perform string concatenation; e.g., the following two
      expressions are equivalent:

      ```
      expr_a || expr_b || expr_c
      ```

      ```
      CONCAT(CONCAT(expr_a, expr_b), expr_c)
      ```
    </Tip>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>CONCAT(CONCAT('ABC','123'),'!')</code></td>
            <td><code>ABC123!</code></td>
          </tr>

          <tr>
            <td><code>'ABC' || '123' || '!'</code></td>
            <td><code>ABC123!</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="CONCAT_TRUNCATE(expr_a, expr_b)" id="concat_truncate-expr_a-expr_b" defaultOpen>
    Returns the concatenation of `expr_a` and `expr_b`, truncated at
    the maximum size of the larger of `expr_a` and `expr_b`.
    For data columns, the size is explicit; for string constants, the size
    will be the smallest *charN* type that can hold the constant string.

    <Info>
      `CONCAT_TRUNCATE` will not work if any parameter is an
      unrestricted-width string.
    </Info>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>CONCAT\_TRUNCATE('ABC123','!')</code></td>
            <td><code>ABC123!</code></td>
          </tr>

          <tr>
            <td><code>CONCAT\_TRUNCATE('AB','CDE')</code></td>
            <td><code>ABCD</code> *(char4 is* *the minimum size* *required to hold the* <code>CDE</code> *value, so* *the result is truncated* *at 4 characters)*</td>
          </tr>

          <tr>
            <td><code>CONCAT\_TRUNCATE('ABCD1234','DEFG')</code></td>
            <td><code>ABCD1234</code> *(an 8-character string* *is the minimum size* *required to hold the* <code>ABCD1234</code> *value, so* *no characters can be* *appended)*</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="CONTAINS(match, expr)" id="contains-match-expr" defaultOpen>
    Returns `1` if `expr` contains `match` by
    string-literal comparison; otherwise, returns `0`
  </Accordion>

  <Accordion title="CONV(expr, from_base, to_base)" id="conv-expr-from_base-to_base" defaultOpen>
    Convert the value represented by the `expr` string from one
    numeric base to another.  Base parameters may be \[`2` - `36`].
    Binary, octal and hexadecimal strings may have an optional prefix.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>CONV('42', 10, 16)</code></td>
            <td><code>'2A'</code></td>
          </tr>

          <tr>
            <td><code>CONV('2a', 16, 10)</code></td>
            <td><code>'42'</code></td>
          </tr>

          <tr>
            <td><code>CONV('11', 2, 10)</code></td>
            <td><code>'3'</code></td>
          </tr>

          <tr>
            <td><code>CONV('0o52', 8, 2)</code></td>
            <td><code>'101010'</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="DEC2HEX(expr[, minimum_digits])" id="dec2hex-expr-minimum_digits" defaultOpen>
    Alias for `HEX`
  </Accordion>

  <Accordion title="DIFFERENCE(expr_a, expr_b)" id="difference-expr_a-expr_b" defaultOpen>
    Returns a value between `0` and `4` that represents the difference
    between the sounds of `expr_a` and `expr_b` based on the
    `SOUNDEX()` value of the strings--a value of `4` is the best
    possible sound match
  </Accordion>

  <Accordion title="EDIT_DISTANCE(expr_a, expr_b)" id="edit_distance-expr_a-expr_b" defaultOpen>
    Returns the Levenshtein edit distance between `expr_a` and
    `expr_b`; the lower the value, the more similar the two strings are
  </Accordion>

  <Accordion title="ENDS_WITH(match, expr)" id="ends_with-match-expr" defaultOpen>
    Returns `1` if `expr` ends with `match` by
    string-literal comparison; otherwise, returns `0`
  </Accordion>

  <Accordion title="FROM_HEX(expr)" id="from_hex-expr" defaultOpen>
    Alias for `UNHEX`
  </Accordion>

  <Accordion title="HEX(expr[, minimum_digits])" id="hex-expr-minimum_digits" defaultOpen>
    Convert the value represented by `expr` into a hexadecimal string
    representation.  Use optional `minimum_digits` to add leading 0s
    when needed; defaults to 1.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>HEX(42)</code></td>
            <td><code>'2A'</code></td>
          </tr>

          <tr>
            <td><code>HEX(42, 8)</code></td>
            <td><code>'0000002A'</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="HEX2DEC(expr)" id="hex2dec-expr" defaultOpen>
    Alias for `UNHEX`
  </Accordion>

  <Accordion title="INITCAP(expr)" id="initcap-expr" defaultOpen>
    Returns `expr` with the first letter of each word in uppercase
  </Accordion>

  <Accordion title="IPV4_PART(expr, part_num)" id="ipv4_part-expr-part_num" defaultOpen>
    Returns the octet of the IP address given in `expr` at the position
    specified by `part_num`.   Valid `part_num` values are constants
    from `1` to `4`.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>IPV4\_PART('12.34.56.78', 1)</code></td>
            <td><code>12</code></td>
          </tr>

          <tr>
            <td><code>IPV4\_PART('12.34.56.78', 4)</code></td>
            <td><code>78</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="IS_IPV4(expr)" id="is_ipv4-expr" defaultOpen>
    Returns `1` if `expr` is an IPV4 address; returns `0` otherwise
  </Accordion>

  <Accordion title="ISIPV4(expr)" id="isipv4-expr" defaultOpen>
    Alias for `IS_IPV4`
  </Accordion>

  <Accordion title="LCASE(expr)" id="lcase-expr" defaultOpen>
    Converts `expr` to lowercase
  </Accordion>

  <Accordion title="LEFT(expr, num_bytes)" id="left-expr-num_bytes" defaultOpen>
    Returns the leftmost `num_bytes` bytes from `expr`
  </Accordion>

  <Accordion title="LEN(expr)" id="len-expr" defaultOpen>
    Alias for `LENGTH`
  </Accordion>

  <Accordion title="LENGTH(expr)" id="length-expr" defaultOpen>
    Returns the number of characters in `expr`
  </Accordion>

  <Accordion title="LOCATE(match, expr[, start_pos])" id="locate-match-expr-start_pos" defaultOpen>
    Returns the starting position of the first match of `match` in
    `expr`, starting from position 1 or `start_pos` (if
    specified).  If `match` can't be found or `start_pos` is
    outside the range of letters in `expr`, a `0` is returned.
  </Accordion>

  <Accordion title="LOWER(expr)" id="lower-expr" defaultOpen>
    Alias for `LCASE`
  </Accordion>

  <Accordion title="LPAD(expr, length[, pad])" id="lpad-expr-length-pad" defaultOpen>
    Left pads the given `expr` string with the `pad` string
    to the given `length` of bytes. If `expr` is longer than
    `length`, the return value is shortened to `length` bytes. If
    `length` is larger than 256, it will be truncated to 256 bytes.  The
    default padding character is a space.

    <Warning>
      The use of multi-byte characters in this function may
      have unexpected results.
    </Warning>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>LPAD('test', 9, 'pad')</code></td>
            <td><code>padpatest</code></td>
          </tr>

          <tr>
            <td><code>LPAD('test', 3, 'pad')</code></td>
            <td><code>tes</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="LTRIM(expr)" id="ltrim-expr" defaultOpen>
    Removes whitespace from the left side of `expr`
  </Accordion>

  <Accordion title="OCT(expr[, minimum_digits])" id="oct-expr-minimum_digits" defaultOpen>
    Convert the value represented by `expr` into an octal (base 8)
    string representation.  Use optional `minimum_digits` to add leading
    0s when needed; defaults to 1.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>OCT(42)</code></td>
            <td><code>'52'</code></td>
          </tr>

          <tr>
            <td><code>OCT(42, 8)</code></td>
            <td><code>'00000052'</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="POSITION(match IN expr)" id="position-match-in-expr" defaultOpen>
    Returns the starting position of the first match of `match` in
    `expr`, starting from position 1.  If `match` can't be
    found, a `0` is returned.
  </Accordion>

  <Accordion title="REGEXP_COUNT (expr, regex[, position [, mode]])" id="regexp_count-expr-regex-position-mode" defaultOpen>
    Returns a count of the number of times the `regex` pattern is
    matched in `expr`.  Matches do not overlap, so the start of a future
    match must start after the end of the previous match.

    The `regex` parameter is the regular expression to try to match.
    It must be a string-literal with 256 characters or fewer.  Generally,
    POSIX-compliant regular expressions are supported for `regex`.
    The escape character used to match wildcards in the `expr` literally
    is `\`.  See `REGEXP_LIKE` for more regular expression examples.

    The optional `position` parameter specifies where to start searching
    in `expr` for the first match.  The first character in the string
    has a `position` of `1` (the default).

    The optional `mode` parameter is a string which can be empty
    (the default) for the default behavior.  See `REGEXP_LIKE` for the
    list of supported mode flags.

    Examples of `REGEXP_COUNT`:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>REGEXP\_COUNT('abababab', 'abab')</code></td>
            <td>2</td>
          </tr>

          <tr>
            <td><code>REGEXP\_COUNT('abababab', 'abab', 2)</code></td>
            <td>1</td>
          </tr>

          <tr>
            <td><code>REGEXP\_COUNT('don''t', 'DON''T', 1, 'i')</code></td>
            <td>1</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="REGEXP_INSTR (expr, regex [, position [, occurrence [, begin_end [, mode [,group]]]]])" id="regexp_instr-expr-regex-position-occurrence-begin_end-mode-group" defaultOpen>
    Returns the starting position (1-based) in `expr` where a `regex`
    match is found.  If no match is found, `0` is returned.

    The `regex` parameter is the regular expression to try to match.
    It must be a string-literal with 256 characters or fewer.  Generally,
    POSIX-compliant regular expressions are supported for `regex`.
    The escape character used to match wildcards in the `expr` literally
    is `\`.  See `REGEXP_LIKE` for more regular expression examples.

    The optional `position` parameter specifies where to start searching
    in `expr` for the first match.  The first character in the string
    has a `position` of `1` (the default).

    The optional `occurrence` parameter specifies which occurrence of
    the `regex` match is desired.  For example, `2` would return the
    second occurrence of `regex` in `expr`.  Matches do not overlap,
    so the start of a future match must start after the end of the
    previous match.

    The optional `begin_end` parameter specifies if the beginning or
    ending position is desired.  Use `0` (the default) for the beginning
    of the match and use `1` for the position after the end of the
    match.

    The optional `mode` parameter is a string which can be empty
    (the default) for the default behavior.  See `REGEXP_LIKE` for the
    list of supported mode flags.

    The optional `group` parameter specifies which regular expression
    group's (i.e., parentheses inside `regex`) beginning/ending position
    to return.  The default of `0` uses the entire matched expression,
    while a `group` of `1`  through `9` corresponds to the 1st group
    up through the 9th group of the match.

    Examples of `REGEXP_INSTR`:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>REGEXP\_INSTR('abcdefg', 'bc')</code></td>
            <td>2</td>
          </tr>

          <tr>
            <td><code>REGEXP\_INSTR('abcdefg', 'ab', 2)</code></td>
            <td>0</td>
          </tr>

          <tr>
            <td><code>REGEXP\_INSTR('abcabc', 'a', 1, 2)</code></td>
            <td>4</td>
          </tr>

          <tr>
            <td><code>REGEXP\_INSTR('abcabc', 'abc', 1, 1, 1)</code></td>
            <td>4</td>
          </tr>

          <tr>
            <td><code>REGEXP\_INSTR('abcabc', 'B C', 1, 1, 0, 'ix')</code></td>
            <td>2</td>
          </tr>

          <tr>
            <td><code>REGEXP\_INSTR('abcdefg', '(C(.(.)))', 1, 1, 0, 'i', 3)</code></td>
            <td>5</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="REGEXP_LIKE(expr, regex[, mode])" id="regexp_like-expr-regex-mode" defaultOpen>
    Returns whether `expr` matches the given `regex`.  Generally,
    POSIX-compliant regular expressions are supported.

    The optional `mode` parameter is a string which can be empty
    (the default) for the default behavior.  It can contain the following
    letters for the associated optional modified behaviors:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Letter</th>
            <th>Meaning</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>i</code></td>
            <td>Case-insensitive matches</td>
          </tr>

          <tr>
            <td><code>m</code></td>
            <td>Treat input as multiple lines so <code>^</code> and <code>\$</code> match around newlines and not just the beginning and ending of the string</td>
          </tr>

          <tr>
            <td><code>n</code></td>
            <td>Allows <code>.</code> to also match a newline character</td>
          </tr>

          <tr>
            <td><code>x</code></td>
            <td>Ignore any whitespace (e.g., spaces) in <code>regex</code></td>
          </tr>
        </tbody>
      </table>
    </div>

    The escape character used to match wildcards in the `expr` literally
    is `\`.

    <Info>
      The `regex` can match the `expr` partially.  To perform
      full matches, `^` and `$` can be used to match the
      start and end of `expr`, respectively.
    </Info>

    Examples of successful matches:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Match Type</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>REGEXP\_LIKE('partial', 'part')</code></td>
            <td>Partial</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('Case', 'cAsE', 'i')</code></td>
            <td>Case-insensitive</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('dot', 'd.t')</code></td>
            <td>Any character</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('range', 'ra\[a-z]ge')</code></td>
            <td>Character range</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('zeroorone', 'z?zer(oor)?one')</code></td>
            <td>0 or 1 token</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('zeroormore', 'z\*zer(\[om]or)\*e')</code></td>
            <td>0 or more tokens</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('oneormore', 'o+n(\[em]or)+e')</code></td>
            <td>1 or more tokens</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('A to Z', '^A.\*Z\$')</code></td>
            <td>Begin/End</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('41ph4Num', '^\[\[:alnum:]]+\$')</code></td>
            <td>Character class</td>
          </tr>

          <tr>
            <td><code>REGEXP\_LIKE('Escape?', 'Escape?')</code></td>
            <td>Escape wildcard</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="REGEXP_MATCH(expr, regex[, options])" id="regexp_match-expr-regex-options" defaultOpen>
    Alias for `REGEXP_LIKE`
  </Accordion>

  <Accordion title="REGEXP_REPLACE (expr, regex [, replace [, position [, occurrence [, mode]]]])" id="regexp_replace-expr-regex-replace-position-occurrence-mode" defaultOpen>
    Returns the `expr` string after replacing `regex` matches with the
    `replace` string parameter.

    The `regex` parameter is the regular expression to try to match.
    It must be a string-literal with 256 characters or fewer.  Generally,
    POSIX-compliant regular expressions are supported for `regex`.
    The escape character used to match wildcards in the `expr` literally
    is `\`.  See `REGEXP_LIKE` for more regular expression examples.

    The `replace` parameter is the optional text with which to replace
    each match of `regex` in `expr`.  The default is an empty string,
    which will simply remove the specified occurrences of `regex` in
    `expr`.  A `replace` of `\0` will insert the entire matched
    expression, while a `replace` of `\1` through `\9` will use the
    corresponding matched grouping (parentheses inside `regex`) as the
    replacement text.

    The optional `position` parameter specifies where to start searching
    in `expr` for the first match.  The first character in the string
    has a `position` of `1` (the default).

    The optional `occurrence` parameter specifies which occurrence of
    the `regex` match to replace.  For example, `2` would only replace
    the second occurrence of `regex` in `expr`.  Matches do not
    overlap, so the start of a future match must start after the end of
    the previous match.  Use `0` (the default) to replace all
    occurrences.

    The optional `mode` parameter is a string which can be empty
    (the default) for the default behavior.  See `REGEXP_LIKE` for the
    list of supported mode flags.

    Examples of `REGEXP_REPLACE`:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>REGEXP\_REPLACE('abc', 'b')</code></td>
            <td>ac</td>
          </tr>

          <tr>
            <td><code>REGEXP\_REPLACE('abc', 'b.', 'x')</code></td>
            <td>ax</td>
          </tr>

          <tr>
            <td><code>REGEXP\_REPLACE('abcd', '.', 'x', 3, 1)</code></td>
            <td>abxd</td>
          </tr>

          <tr>
            <td><code>REGEXP\_REPLACE('abcd', '(b(.))', '-\2-')</code></td>
            <td>a-c-d</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="REGEXP_SUBSTR (expr, regex [, position [, occurrence [, mode [,group]]]])" id="regexp_substr-expr-regex-position-occurrence-mode-group" defaultOpen>
    Returns the portion of the `expr` string that matched `regex`.
    An empty string is returned if no match is found.

    The `regex` parameter is the regular expression to try to match.
    It must be a string-literal with 256 characters or fewer.  Generally,
    POSIX-compliant regular expressions are supported for `regex`.
    The escape character used to match wildcards in the `expr` literally
    is `\`.  See `REGEXP_LIKE` for more regular expression examples.

    The optional `position` parameter specifies where to start searching
    in `expr` for the first match.  The first character in the string
    has a `position` of `1` (the default).

    The optional `occurrence` parameter specifies which occurrence of
    the `regex` match is desired.  For example, `2` would return the
    second occurrence of `regex` in `expr`.  Matches do not overlap,
    so the start of a future match must start after the end of the
    previous match.

    The optional `mode` parameter is a string which can be empty
    (the default) for the default behavior.  See `REGEXP_LIKE` for the
    list of supported mode flags.

    The optional `group` parameter specifies which regular expression
    grouping (i.e., parentheses inside `regex`) to use.  The default of
    `0` uses the entire matched expression, while a `group` of `1`
    through `9` corresponds to the 1st group up through the 9th group of
    the match.

    Examples of `REGEXP_SUBSTR`:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>REGEXP\_SUBSTR('abcdefg', 'b.')</code></td>
            <td>bc</td>
          </tr>

          <tr>
            <td><code>REGEXP\_SUBSTR('abcadeafghij', 'a...', 2, 1)</code></td>
            <td>adea</td>
          </tr>

          <tr>
            <td><code>REGEXP\_SUBSTR('abcadeafghij', 'a...', 1, 2)</code></td>
            <td>afgh</td>
          </tr>

          <tr>
            <td><code>REGEXP\_SUBSTR('abcdefg', '(C(.(.)))', 1, 1, 'i', 3)</code></td>
            <td>e</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="REPLACE(expr, match, repl)" id="replace-expr-match-repl" defaultOpen>
    Replaces every occurrence of `match` in `expr` with `repl`
  </Accordion>

  <Accordion title="REPLACE_CHAR(expr, match, repl)" id="replace_char-expr-match-repl" defaultOpen>
    Replaces every occurrence of the single-byte character `match` in
    `expr` with the single-byte character `repl`
  </Accordion>

  <Accordion title="REPLACE_TRUNCATE(expr, match, repl)" id="replace_truncate-expr-match-repl" defaultOpen>
    Replaces every occurrence of `match` in `expr` with `repl`, and
    then truncates the resulting string at 256 bytes if it is longer than
    that

    <Info>
      `REPLACE_TRUNCATE` will not work if any parameter is an
      unrestricted-width string.
    </Info>

    <Warning>
      The use of multi-byte characters in this function may
      have unexpected results.
    </Warning>
  </Accordion>

  <Accordion title="REVERSE(expr)" id="reverse-expr" defaultOpen>
    Returns `expr` with the order of bytes reversed.

    <Warning>
      The use of multi-byte characters in this function may
      have unexpected results.
    </Warning>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>REVERSE('Reverse')</code></td>
            <td><code>esreveR</code></td>
          </tr>

          <tr>
            <td><code>REVERSE('Was it a bat I saw?')</code></td>
            <td><code>?was I tab a ti saW</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="RIGHT(expr, num_bytes)" id="right-expr-num_bytes" defaultOpen>
    Returns the rightmost `num_bytes` bytes from `expr`
  </Accordion>

  <Accordion title="RPAD(expr, length, pad)" id="rpad-expr-length-pad" defaultOpen>
    Right pads the given `expr` string with the `pad` string
    to the given `length` of bytes. If `expr` is longer than
    `length`, the return value is shortened to `length` bytes. If
    `length` is larger than 256, it will be truncated to 256 bytes.  The
    default padding character is a space.

    <Warning>
      The use of multi-byte characters in this function may
      have unexpected results.
    </Warning>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>RPAD('test', 9, 'pad')</code></td>
            <td><code>testpadpa</code></td>
          </tr>

          <tr>
            <td><code>RPAD('test', 3, 'pad')</code></td>
            <td><code>tes</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="RTRIM(expr)" id="rtrim-expr" defaultOpen>
    Removes whitespace from the right side of `expr`
  </Accordion>

  <Accordion title="SOUNDEX(expr)" id="soundex-expr" defaultOpen>
    Returns a soundex value from `expr`. Only the first word in the
    string will be considered in the calculation.

    <Info>
      This is the algorithm used by most programming languages.
    </Info>
  </Accordion>

  <Accordion title="SPACE(n)" id="space-n" defaultOpen>
    Returns a string consisting of `n` space characters. The value of
    `n` can only be within the range of 0-256.
  </Accordion>

  <Accordion title="SPLIT(expr, delim, group_num)" id="split-expr-delim-group_num" defaultOpen>
    Splits `expr` into groups delimited by the `delim` single-byte
    character and returns the `group_num` split group.  If `group_num`
    is positive, groups will be counted from the beginning of `expr`; if
    negative, groups will be counted from the end of `expr` going
    backwards.  Two consecutive delimiters will result in an empty string
    being added to the list of selectable groups.  If no instances of
    `delim` exist in `expr`, the entire string is available at group
    `1` (and `-1`).  Group `0` returns nothing.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>SPLIT('apple', 'p', 1)</code></td>
            <td><code>a</code></td>
          </tr>

          <tr>
            <td><code>SPLIT('apple', 'p', 2)</code></td>
            <td>*\<empty string>*</td>
          </tr>

          <tr>
            <td><code>SPLIT('apple', 'p', -1)</code></td>
            <td><code>le</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="STARTS_WITH(match, expr)" id="starts_with-match-expr" defaultOpen>
    Returns `1` if `expr` starts with `match` by
    string-literal comparison; otherwise, returns `0`
  </Accordion>

  <Accordion title="STRCMP(expr_a, expr_b)" id="strcmp-expr_a-expr_b" defaultOpen>
    Compares `expr_a` to `expr_b` in a lexicographical sort

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Situation</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>expr\_a</code> and <code>expr\_b</code> are the same</td>
            <td><code>0</code></td>
          </tr>

          <tr>
            <td><code>expr\_a</code> comes before <code>expr\_b</code>, lexicographically</td>
            <td><code>-1</code></td>
          </tr>

          <tr>
            <td><code>expr\_a</code> comes after <code>expr\_b</code>, lexicographically</td>
            <td><code>1</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="SUBSTR(expr, start_pos[, num_chars])" id="substr-expr-start_pos-num_chars" defaultOpen>
    Alias for `SUBSTRING`
  </Accordion>

  <Accordion title="SUBSTRING(expr, start_pos[, num_bytes])" id="substring-expr-start_pos-num_bytes" defaultOpen>
    Returns `num_bytes` bytes from the `expr`, starting at the 1-based
    `start_pos` byte.  If `num_bytes` is not specified, all bytes
    after `start_pos` will be returned.

    <Warning>
      The use of multi-byte characters in this function may
      have unexpected results.
    </Warning>

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>SUBSTRING('banana', 3)</code></td>
            <td><code>nana</code></td>
          </tr>

          <tr>
            <td><code>SUBSTRING('banana', 3, 2)</code></td>
            <td><code>na</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="TO_HEX(expr[, minimum_digits])" id="to_hex-expr-minimum_digits" defaultOpen>
    Alias for `HEX`
  </Accordion>

  <Accordion title="TRIM(expr)" id="trim-expr" defaultOpen>
    Removes whitespace from both sides of `expr`
  </Accordion>

  <Accordion title="UCASE(expr)" id="ucase-expr" defaultOpen>
    Converts `expr` to uppercase
  </Accordion>

  <Accordion title="UNHEX(expr)" id="unhex-expr" defaultOpen>
    Convert the hexadecimal string `expr` into a (decimal) number.

    Examples:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>UNHEX('42')</code></td>
            <td><code>66</code></td>
          </tr>

          <tr>
            <td><code>UNHEX('1A')</code></td>
            <td><code>26</code></td>
          </tr>

          <tr>
            <td><code>UNHEX('1a')</code></td>
            <td><code>26</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="UPPER(expr)" id="upper-expr" defaultOpen>
    Alias for `UCASE`
  </Accordion>
</AccordionGroup>

<a id="sql-string-functions-agg" />

### Aggregation Functions

The following functions can be used on *string* columns within
[aggregations](/content/sql/query#sql-aggregation).

These functions can be used to convert string column values into delimited lists
of those values.

<AccordionGroup>
  <Accordion title="STRING_AGG(expr[, delim])" id="string_agg-expr-delim" defaultOpen>
    Combines column values within a group into a single delimited *string* of those values.

    The default delimiter is a comma.
  </Accordion>

  <Accordion title="STRING_AGG_DISTINCT(expr[, delim])" id="string_agg_distinct-expr-delim" defaultOpen>
    Combines column values within a group into a single delimited *string* of those values,
    removing any duplicates.

    The default delimiter is a comma.
  </Accordion>
</AccordionGroup>

<a id="sql-string-functions-like" />

### LIKE / ILIKE

Simple pattern-matching capability is provided through the use of the `LIKE` and `ILIKE`
clauses, for [string columns](/content/sql/ddl#sql-column-types).  `LIKE` is case-sensitive,
while `ILIKE` is case-insensitive.

```sql title="LIKE / ILIKE Syntax" theme={null}
<expr> [NOT] <LIKE | ILIKE> <match> [ESCAPE '<esc_char>']
```

This clause matches records where reference expression `expr` does (or does
`NOT`) match the string value of `match`.  The match is a string literal
one, with the following exceptions:

* `%` matches any string of 0 or more characters
* `_` matches any single character
* `[<character_set>]` matches any single character listed in the set.  The
  `character_set` may contain ranges using a dash (`-`).  A
  `character_set` starting with `^` will match any character not in the
  specified set.

By default, there is no escape character.  Use the `ESCAPE` clause to specify
an escape character.  The escape character is used to match special characters
in the `expr` literally.  For example, `~%` will match the `%` character
if `~` is the escape character.

To search for employees whose last name starts with *C*, ends with *a*, and has
exactly five letters:

```sql LIKE Single Character Case-Sensitive Match Example theme={null}
SELECT *
FROM example.employee
WHERE last_name LIKE 'C___a'
```

To search for employees whose first name does not start with *Brook*, regardless
of case:

```sql ILIKE Multiple Character Case-Insensitive Match Example theme={null}
SELECT *
FROM example.employee
WHERE first_name NOT ILIKE 'brook%'
```

To search for employees whose first name has a capital letter after the first
letter:

```sql LIKE Character Range Case-Sensitive Match Example theme={null}
SELECT *
FROM example.employee
WHERE first_name LIKE '%_[A-Z]%'
```

To search for employees whose first name does not contain an underscore,
redefining the default escape character to a `~` to escape the underscore:

```sql ILIKE Custom Escape Character Case-Insensitive Match Example theme={null}
SELECT *
FROM example.employee
WHERE first_name NOT ILIKE '%~_%' ESCAPE '~'
```

<a id="sql-string-functions-fts" />

### FILTER\_BY\_STRING

The `FILTER_BY_STRING` table function allows for several types of pattern
matching for [fixed-width string columns](/content/sql/ddl#sql-column-types)
(`VARCHAR(1)` - `VARCHAR(256)`), as well as
[full text search](/content/concepts/full_text_search) capability for all
string columns with the `TEXT_SEARCH`
[column property](/content/sql/ddl#sql-column-properties).  Its features are based
on the [/filter/bystring](/content/api/rest/filter_bystring_rest) endpoint.

The basic form of the `FILTER_BY_STRING` function when called in a `SELECT`
statement follows.

```sql title="FILTER_BY_STRING Table Function Syntax" theme={null}
SELECT *
FROM TABLE
(
	FILTER_BY_STRING
	(
		TABLE_NAME => INPUT_TABLE(<table name | select statement>),
		[COLUMN_NAMES => '<column list>',]
		MODE => '<filter type>',
		EXPRESSION => '<filter expression>',
		[OPTIONS => KV_PAIRS('<option name>' = '<option value>'[,...])]
	)
)
```

The basic form of the `FILTER_BY_STRING` function when called in an
`EXECUTE FUNCTION` statement follows.  When called this way, the results are
saved in the specified *view*.

```sql title="FILTER_BY_STRING Execute Function Syntax" theme={null}
EXECUTE FUNCTION FILTER_BY_STRING
(
	TABLE_NAME => INPUT_TABLE(<table name | select statement>),
	VIEW_NAME => '[<schema name>.]<view name>',
	[COLUMN_NAMES => '<column list>',]
	MODE => '<filter type>',
	EXPRESSION => '<filter expression>',
	[OPTIONS => KV_PAIRS('<option name>' = '<option value>'[,...])]
)
```

<AccordionGroup>
  <Accordion title="TABLE_NAME" id="table_name" defaultOpen>
    The data set to filter, which should be passed via query to the `INPUT_TABLE` function.

    To perform a string filter on a column in the *customer* table, pass the name of the table to
    `INPUT_TABLE`:

    ```
    INPUT_TABLE(customer)
    ```

    To perform a string filter on a column in the result of a query, pass the query to `INPUT_TABLE`:

    ```
    INPUT_TABLE(SELECT * FROM customer_west UNION SELECT * FROM customer_east)
    ```
  </Accordion>

  <Accordion title="VIEW_NAME" id="view_name" defaultOpen>
    Name of the view in which the results are to be stored, in \[schema\_name.]table\_name format,
    using standard [name resolution rules](/content/sql/naming#sql-name-resolution) and meeting
    [table naming criteria](/content/sql/naming#sql-naming-criteria)

    <Note>
      This parameter is only applicable when using `EXECUTE FUNCTION` syntax.
    </Note>
  </Accordion>

  <Accordion title="COLUMN_NAMES" id="column_names" defaultOpen>
    Comma-separated list of columns to which the filter will be applied.

    <Note>
      Omit this parameter when using the `search` filter `MODE`.
    </Note>
  </Accordion>

  <Accordion title="MODE" id="mode" defaultOpen>
    Type of string filter to apply:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Mode</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>contains</code></td>
            <td>Partial substring match *(not accelerated)*. If the column is a string type (non-charN) and the number of records is too large, it will return 0.</td>
          </tr>

          <tr>
            <td><code>equals</code></td>
            <td>Exact whole-string match *(accelerated)*.</td>
          </tr>

          <tr>
            <td><code>regex</code></td>
            <td>Full regular expression search *(not accelerated)*. If the column is a string type (non-charN) and the number of records is too large, it will return 0.</td>
          </tr>

          <tr>
            <td><code>search</code></td>
            <td>Full text search with wildcards and boolean operators, for string columns (<code>VARCHAR</code>) that have the <code>TEXT\_SEARCH</code> [column property](/content/sql/ddl#sql-column-properties) applied. See [Full Text Search](/content/concepts/full_text_search) for syntax & grammar detail. <Note>Omit the `COLUMN_NAMES` parameter when using this `MODE`. All text-searchable string columns will be searched.  Also, only a table name can be used for `TABLE_NAME`--a query cannot be used.</Note></td>
          </tr>

          <tr>
            <td><code>starts\_with</code></td>
            <td>Match strings that start with the given expression *(not accelerated)*. If the column is a string type (non-charN) and the number of records is too large, it will return 0.</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="EXPRESSION" id="expression" defaultOpen>
    String literal or pattern, depending on `MODE` selected, to use in filtering string columns
  </Accordion>

  <Accordion title="OPTIONS" id="options" defaultOpen>
    Optional list of string filtering options, specified as a set of key/value pairs passed as a
    comma-delimited list of `<key> = '<value>'` assignments to the `KV_PAIRS` function; e.g.:

    ```
    KV_PAIRS(case_sensitive = 'false')
    ```

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Option</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>case\_sensitive</code></td>
            <td>If *true*, the filter will be case-sensitive; if false, case-insensitive. <Note>Not applicable when `MODE` is `search`.</Note></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>
</AccordionGroup>

To see the message text & time for events in the *event\_log* table containing
the word *ERROR*:

```sql FILTER_BY_STRING Example theme={null}
SELECT *
FROM TABLE
(
    FILTER_BY_STRING
    (
        TABLE_NAME => INPUT_TABLE(SELECT event_time, message FROM example.event_log),
        COLUMN_NAMES => 'message',
        MODE => 'contains',
        EXPRESSION => 'ERROR'
    )
)
```

<a id="sql-functions-security" />

## User/Security Functions

<AccordionGroup>
  <Accordion title="CURRENT_SCHEMA()" id="current_schema" defaultOpen>
    Returns the default schema of the current user
  </Accordion>

  <Accordion title="CURRENT_USER()" id="current_user" defaultOpen>
    Alias for `USER`
  </Accordion>

  <Accordion title="HASH(column[, seed])" id="hash-column-seed" defaultOpen>
    Returns a non-negative integer representing an obfuscated version
    of `column`, using the given `seed`; default `seed` is `0`
  </Accordion>

  <Accordion title="IS_MEMBER(role[, user/role])" id="is_member-role-user/role" defaultOpen>
    Returns whether the current user (or the given `user/role`,
    if specified) has been assigned the given `role`, either
    directly or indirectly:

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Situation</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td>Current user (or given <code>user/role</code>) has been granted <code>role</code></td>
            <td><code>true</code></td>
          </tr>

          <tr>
            <td>Current user (or given <code>user/role</code>) has not been granted <code>role</code></td>
            <td><code>false</code></td>
          </tr>

          <tr>
            <td>Role <code>role</code> does not exist</td>
            <td>*null*</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="IS_ROLEMEMBER(role[, user/role])" id="is_rolemember-role-user/role" defaultOpen>
    Alias for `IS_MEMBER`
  </Accordion>

  <Accordion title="MASK(expr, start, length[, char])" id="mask-expr-start-length-char" defaultOpen>
    Masks `length` bytes of `expr`, beginning at the byte position
    identified by `start`, with `*` characters (or the single-byte
    character specified in `char`):

    <Warning>
      The use of multi-byte characters in this function may
      have unexpected results.
    </Warning>

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Function Call</th>
            <th>Result</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>MASK('Characters', 4, 5)</code></td>
            <td><code>Cha\*\*\*\*\*rs</code></td>
          </tr>

          <tr>
            <td><code>MASK('Characters', 5, 2, '#')</code></td>
            <td><code>Char##ters</code></td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="NEW_UUID()" id="new_uuid" defaultOpen>
    Returns a randomly-generated UUID
  </Accordion>

  <Accordion title="OBFUSCATE(column[, seed])" id="obfuscate-column-seed" defaultOpen>
    Alias for `HASH`
  </Accordion>

  <Accordion title="SHA256(expr)" id="sha256-expr" defaultOpen>
    Returns the hex digits of the SHA-256 hash of the given value
    `expr` as a `char64` string.
  </Accordion>

  <Accordion title="SYSTEM_USER()" id="system_user" defaultOpen>
    Alias for `USER`
  </Accordion>

  <Accordion title="USER()" id="user" defaultOpen>
    Returns the username of the current user
  </Accordion>
</AccordionGroup>

<a id="sql-aggregation-functions" />

## Aggregation Functions

These functions can be applied to [aggregate](/content/sql/query#sql-aggregation)
data. They include:

* [Array Aggregation Functions](/content/sql/query#sql-array-functions-agg)
* [Geospatial/Geometry Aggregation Functions](/content/sql/query#sql-geo-functions-aggregation)
* [JSON Aggregation Functions](/content/sql/query#sql-json-functions-agg)
* [Lookup/Grouping Aggregation Functions](/content/sql/query#sql-lookup-functions-agg)
* [Math Aggregation Functions](/content/sql/query#sql-math-functions-agg)
* [String Aggregation Functions](/content/sql/query#sql-string-functions-agg)

<a id="sql-lookup-functions-agg" />

### Lookup/Grouping Functions

<AccordionGroup>
  <Accordion title="ARG_MAX(agg_expr, ret_expr)" id="arg_max-agg_expr-ret_expr" defaultOpen>
    The value of `ret_expr` where `agg_expr` is the maximum
    value (e.g. `ARG_MAX(cost, product_id)` returns the product
    ID of the highest cost product). `ARG_MAX(a, b)` is equivalent to
    `LAST(b, a)`.
  </Accordion>

  <Accordion title="ARG_MIN(agg_expr, ret_expr)" id="arg_min-agg_expr-ret_expr" defaultOpen>
    The value of `ret_expr` where `agg_expr` is the minimum
    value (e.g. `ARG_MIN(cost, product_id)` returns the product
    ID of the lowest cost product). `ARG_MIN(a, b)` is equivalent to
    `FIRST(b, a)`.
  </Accordion>

  <Accordion title="ATTR(expr)" id="attr-expr" defaultOpen>
    If `MIN(expr)` = `MAX(expr)`, returns `expr`; otherwise
    `*`

    <Info>
      `expr` must resolve to a string type, and must be casted
      to one, if not already
    </Info>
  </Accordion>

  <Accordion title="FIRST(ret_expr, agg_expr)" id="first-ret_expr-agg_expr" defaultOpen>
    The value of `ret_expr` where `agg_expr` is the minimum
    value (e.g. `FIRST(product_id, cost)` returns the product ID
    ID of the lowest cost product). `FIRST(a, b)` is equivalent to
    `ARG_MIN(b,a)`
  </Accordion>

  <Accordion title="GROUPING(expr)" id="grouping-expr" defaultOpen>
    Used primarily with [ROLLUP](/content/sql/query#sql-grouping-rollup),
    [CUBE](/content/sql/query#sql-grouping-cube), and
    [GROUPING SETS](/content/sql/query#sql-grouping-groupingsets), to distinguish the source of
    *null* values in an aggregated result set, returns whether
    `expr` is part of the aggregation set used to calculate the
    values in a given result set row.  Returns `0` if `expr`
    is part of the row's aggregation set, `1` if `expr` is not
    (meaning that aggregation took place across all `expr`
    values).

    For example, in a `ROLLUP(A)` operation, there will be two
    potential rows with *null* in the result set for column `A`.
    One row will contain *null* values of `A` aggregated
    together, and the other will contain *null*, but be an
    aggregation over the entire table, irrespective of `A`
    values.  In this case, `GROUPING(A)` will return `0` for
    the *null* values of `A` aggregated together (as well as all
    other grouped `A` values) and `1` for the row resulting
    from aggregating across all `A` values.
  </Accordion>

  <Accordion title="LAST(ret_expr, agg_expr)" id="last-ret_expr-agg_expr" defaultOpen>
    The value of `ret_expr` where `agg_expr` is the maximum
    value (e.g. `LAST(product_id, cost)` returns the product
    ID of the highest cost product). `LAST(a, b)` is equivalent to
    `ARG_MAX(b, a)`.
  </Accordion>
</AccordionGroup>

<a id="sql-grouping-functions" />

## Grouping Functions

These functions can be applied to [group](/content/sql/query#sql-grouping) data.

<AccordionGroup>
  <Accordion title="ROLLUP(expr)" id="rollup-expr" defaultOpen>
    Calculates *n* + 1 aggregates for *n* number of columns in `expr`
  </Accordion>

  <Accordion title="CUBE(expr)" id="cube-expr" defaultOpen>
    Calculates 2<sup>n</sup> aggregates for *n* number of columns in `expr`
  </Accordion>

  <Accordion title="GROUPING SETS(expr)" id="grouping-sets-expr" defaultOpen>
    Calculates aggregates for any given aggregates in `expr`, including `ROLLUP()` and
    `CUBE()`
  </Accordion>
</AccordionGroup>

<a id="sql-ml-functions" />

## ML Functions

There are two supported machine learning functions:

* [PREDICT](/content/sql/query#sql-ml-functions-predict)
* [OUTLIERS](/content/sql/query#sql-ml-functions-outliers)

<a id="sql-ml-functions-predict" />

### PREDICT

The `PREDICT` table function will predict the values of the dependent
variables that correspond to a given column of independent variables, using a
given base table containing "historical" values of each.  This table will be
used as the basis to calculate the prediction.

To make the prediction, the slope & y-intercept of the least-squares-fit linear
equation of the base table data will be calculated.  Then, that line will be
used to calculate the dependent variable for each given independent variable,
and the values of each will be returned in the result set as `Y` and `X`,
respectively.

The basic form of the `PREDICT` function, called within a `SELECT` statement
follows.

```sql title="PREDICT Table Function Syntax" theme={null}
SELECT x, y FROM TABLE
(
	PREDICT
	(
		HISTORY_TABLE     => INPUT_TABLE(<table name | select statement>),
		X_COLUMN          => < '<column name>' | <column position> >,
		Y_COLUMN          => < '<column name>' | <column position> >,
		PREDICT_ON_TABLE  => INPUT_TABLE(<table name | select statement>),
		PREDICT_ON_COLUMN => < '<column name>' | <column position> >,
		[PREDICT_METHOD   => 'LINEAR']
	)
)
```

<AccordionGroup>
  <Accordion title="HISTORY_TABLE" id="history_table" defaultOpen>
    The name of the table containing the "historical" data upon which the prediction will be made.

    To make a prediction from the data based on the *ticket\_prices* table, pass the name of the table
    to `INPUT_TABLE`:

    ```
    INPUT_TABLE(ticket_prices)
    ```

    To make a prediction from data that is the result of a query, pass the query to `INPUT_TABLE`:

    ```
    INPUT_TABLE
    (
        SELECT * FROM ticket_prices_local
        UNION
        SELECT * FROM ticket_prices_global
    )
    ```
  </Accordion>

  <Accordion title="X_COLUMN" id="x_column" defaultOpen>
    The name or position of the column in `HISTORY_TABLE` containing the independent variable that
    will be used as the basis for the prediction.
  </Accordion>

  <Accordion title="Y_COLUMN" id="y_column" defaultOpen>
    The name or position of the column in `HISTORY_TABLE` containing the dependent variable that
    will be used as the basis for the prediction.
  </Accordion>

  <Accordion title="PREDICT_ON_TABLE" id="predict_on_table" defaultOpen>
    The name of the table containing the independent variable against which the prediction will be
    made.

    To make a prediction against column data in the *future\_years* table, pass the name of the table
    to `INPUT_TABLE`:

    ```
    INPUT_TABLE(future_years)
    ```

    To make a prediction against data that is the result of a query, pass the query to
    `INPUT_TABLE`:

    ```
    INPUT_TABLE
    (
        SELECT * FROM future_years
        UNION
        SELECT * FROM future_decades
    )
    ```
  </Accordion>

  <Accordion title="PREDICT_ON_COLUMN" id="predict_on_column" defaultOpen>
    The name or position of the column in `PREDICT_ON_TABLE` containing the independent variable
    against which the prediction will be made.
  </Accordion>

  <Accordion title="PREDICT_METHOD" id="predict_method" defaultOpen>
    The optional calculation method to use to make the prediction.  The only supported (and default)
    method is `LINEAR`.
  </Accordion>
</AccordionGroup>

To predict ticket prices for years found in the *future\_years* table, based on
historical ticket price data found in the *ticket\_prices* table:

```sql PREDICT Example theme={null}
SELECT * FROM TABLE
(
	PREDICT
	(
		HISTORY_TABLE => INPUT_TABLE(example.ticket_prices),
		X_COLUMN => 'year',
		Y_COLUMN => 'cost',
		PREDICT_ON_TABLE => INPUT_TABLE(example.future_years),
		PREDICT_ON_COLUMN => 'year'
	)
)
```

<a id="sql-ml-functions-outliers" />

### OUTLIERS

The `OUTLIERS` table function will calculate the outliers in a given data set,
based on a specified calculation type, threshold, and partition column.  The
partition column allows the data to be segmented into subsets, one per unique
partition column value, and have the outliers for each subset calculated &
determined independently from other subsets.

The basic form of the `OUTLIERS` function, called within a `SELECT`
statement follows.

```sql title="OUTLIERS Table Function Syntax" theme={null}
SELECT * FROM TABLE
(
	OUTLIERS
	(
		DATA_TABLE        => INPUT_TABLE(<table name | select statement>),
		DATA_COLUMN       => < '<column name>' | <column position> >,
		[PARTITION_COLUMN => < '<column name>' | <column position> >,]
		[OUTLIER_METHOD   => < 'ZSCORE' | 'PERCENTILE' >,]
		[THRESHOLD_LOW    => <threshold value>,]
		[THRESHOLD_HIGH   => <threshold value>,]
		[OUTPUT_DATA      => < 'OUTLIERS' | 'NON_OUTLIERS' | 'ALL' >,]
		[OUTPUT_SCORE     => < TRUE | FALSE >]
	)
)
```

<AccordionGroup>
  <Accordion title="DATA_TABLE" id="data_table" defaultOpen>
    The name of the data table within which outliers will be detected.

    To detect outliers in the data in the *employee* table, pass the name of the table to
    `INPUT_TABLE`:

    ```
    INPUT_TABLE(employee)
    ```

    To detect outliers in the data that is the result of a query, pass the query to `INPUT_TABLE`:

    ```
    INPUT_TABLE
    (
        SELECT * FROM employee_east
        UNION
        SELECT * FROM employee_west
    )
    ```
  </Accordion>

  <Accordion title="DATA_COLUMN" id="data_column" defaultOpen>
    The name or position of the column in `DATA_TABLE` containing the outliers to detect.
  </Accordion>

  <Accordion title="PARTITION_COLUMN" id="partition_column" defaultOpen>
    The name or position of the column in `DATA_TABLE` containing the value to partition over, when
    detecting outliers.  Each unique `PARTITION_COLUMN` value will denote a subset of the source
    data, within which outliers will be determined independently from other subsets.
  </Accordion>

  <Accordion title="OUTLIER_METHOD" id="outlier_method" defaultOpen>
    The optional calculation method to use to detect outliers.  The default method is `ZSCORE`.

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Method</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>ZSCORE</code></td>
            <td>Z-score calculation, indicating the number of standard deviations above the mean each value within the set is.  If a <code>PARTITION\_COLUMN</code> is given, the z-score will be calculated for each subset of data corresponding to a unique <code>PARTITION\_COLUMN</code> value.  The z-score uses the following formula: <pre><code>(DATA\_COLUMN - AVG(DATA\_COLUMN)) / STDDEV(DATA\_COLUMN)
            Scores will be decimals centered around `0`.</code></pre></td>
          </tr>

          <tr>
            <td><code>PERCENTILE</code></td>
            <td>The standard percentile calculation, performed within each <code>PARTITION\_COLUMN</code> group (if specified).  Scores will be decimals between <code>0</code>, inclusive, and <code>100</code>, exclusive.</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="THRESHOLD_LOW" id="threshold_low" defaultOpen>
    The lower bound to use for the determination of outliers.  Records with scores lower than this
    value will be considered outliers.  If not given, no lower bound will be applied.  The value
    should match the `OUTLIER_METHOD` used:

    * `ZSCORE` - Threshold is the negative number of standard deviations to the left of the mean,
      beyond which outliers are found; e.g., `-3` would indicate a threshold of *3* standard
      deviations lower than the mean.
    * `PERCENTILE` - Threshold is the percentage lower than which outliers are found;
      e.g., `25` would indicate outliers have percentile scores below *25%*.
  </Accordion>

  <Accordion title="THRESHOLD_HIGH" id="threshold_high" defaultOpen>
    The upper bound to use for the determination of outliers.  Records with scores higher than this
    value will be considered outliers.  If not given, no upper bound will be applied.  The value
    should match the `OUTLIER_METHOD` used:

    * `ZSCORE` - Threshold is the positive number of standard deviations to the right of the mean,
      beyond which outliers are found; e.g., `3` would indicate a threshold of *3* standard
      deviations higher than the mean.
    * `PERCENTILE` - Threshold is the percentage higher than which outliers are found;
      e.g., `75` would indicate outliers have percentile scores above *75%*.
  </Accordion>

  <Accordion title="OUTLIER_DATA" id="outlier_data" defaultOpen>
    The selection of source records to return in the result set.  The default is `OUTLIERS`.

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Method</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>OUTLIERS</code></td>
            <td>Return only the records that are outliers.</td>
          </tr>

          <tr>
            <td><code>NON\_OUTLIERS</code></td>
            <td>Return only the records that are not outliers.</td>
          </tr>

          <tr>
            <td><code>ALL</code></td>
            <td>Return all records.</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>

  <Accordion title="OUTPUT_SCORE" id="output_score" defaultOpen>
    If `TRUE`, the calculated score for each record will be added to the result set in a column
    named `OUTPUT_SCORE`.
  </Accordion>
</AccordionGroup>

To find the outlier employee salaries in the *employee* table that are
*1 standard deviation* away from the mean, using the *z-score* method:

```sql Outliers Using Z-Score Example theme={null}
SELECT * FROM TABLE
(
	OUTLIERS
	(
		DATA_TABLE     => INPUT_TABLE(example.employee),
		DATA_COLUMN    => 'salary',
		THRESHOLD_LOW  => -1,
		THRESHOLD_HIGH => 1
	)
)
```

To show the percentile for non-outlier employee salaries by department in the
*employee* table, between the *25th* & *75th* percentiles, using the
*percentile* method:

```sql Non-Outliers Using Percentile Example theme={null}
SELECT * FROM TABLE
(
	OUTLIERS
	(
		DATA_TABLE       => INPUT_TABLE(example.employee),
		DATA_COLUMN      => 'salary',
		PARTITION_COLUMN => 'dept_id',
		OUTLIER_METHOD   => 'PERCENTILE',
		THRESHOLD_LOW    => 25,
		THRESHOLD_HIGH   => 75,
		OUTPUT_DATA      => 'NON_OUTLIERS',
		OUTPUT_SCORE     => TRUE
	)
)
```

<a id="sql-distribution-functions" />

## Distribution Functions

[Distribution](/content/concepts/tables#distribution) functions are column expressions that affect the
[sharded](/content/concepts/tables#sharding)/[replicated](/content/concepts/tables#replication) nature of the result
set of a given query.  It may be necessary to force a result set to be
distributed in a certain way for a subsequent operation on that result set to be
performant.

<Note>
  Employing these functions will prevent any automatic resharding
  of data to allow the query to succeed.  Use only when a better query plan
  (with respect to data distribution) is known than any the system can devise.
</Note>

<AccordionGroup>
  <Accordion title="KI_REPLICATE()" id="ki_replicate" defaultOpen>
    Force a scalar result set to be replicated (query/subquery with no `GROUP BY`)
  </Accordion>

  <Accordion title="KI_REPLICATE_GROUP_BY(0)" id="ki_replicate_group_by-0" defaultOpen>
    Force an aggregated result set to be replicated (query/subquery with `GROUP BY`)
  </Accordion>

  <Accordion title="KI_MATCH_COLUMN(0)" id="ki_match_column-0" defaultOpen>
    Aligns the column count of queries that are part of a [UNION](/content/sql/query#sql-union),
    [INTERSECT](/content/sql/query#sql-intersect) or [EXCEPT](/content/sql/query#sql-except) with a query whose column list
    has been amended with either `KI_REPLICATE_GROUP_BY` or `KI_SHARD_KEY`
  </Accordion>

  <Accordion title="KI_SHARD_KEY(<column list>)" id="ki_shard_key-<column-list>" defaultOpen>
    Force the result set to be [sharded](/content/concepts/tables#sharding) on the given columns.
    This will override any implicitly-derived or explicitly-defined
    [replication](/content/concepts/tables#replicated) status the table would have had.

    <Info>
      The column(s) listed in `column list` must also appear in the
      `SELECT` list; `KI_SHARD_KEY` merely identifies which of the
      selected columns should be used as the [shard key](/content/concepts/tables#shard-key).
    </Info>
  </Accordion>
</AccordionGroup>

### Sharding Example

For example, a query for all employees and their total employees managed,
including employees who don't manage anyone, could employ a [UNION](/content/sql/query#sql-union)
like this:

```sql Sharding Example theme={null}
SELECT manager_id, COUNT(*)
FROM example.employee
GROUP BY manager_id
UNION
SELECT id, 0
FROM example.employee
WHERE id NOT IN
	(
		SELECT manager_id
		FROM example.employee
		WHERE manager_id IS NOT NULL
	)
```

In this example, the `employee` table is [sharded](/content/concepts/tables#sharding) on `id`.
Since the first part of the `UNION` aggregates on `manager_id`, the result
will be [replicated](/content/concepts/tables#replication).  The second part of the `UNION` does
no aggregation and includes the [shard key](/content/concepts/tables#shard-key) in the `SELECT`
list; the result of this will be *sharded*.

Prior to *Kinetica v7.0*, the [limitation](/content/concepts/unions#union-limitations) of `UNION`
operations requiring that both parts of a `UNION` have to be distributed the
same way, would make the query fail, with the following message:

```
GPUdb Error: either all input tables must be replicated or all input tables
must be non-replicated
```

In order to work around this limitation, a *distribution function* could be
used.  This is what the SQL engine of *Kinetica*, versions *7.0* or later, do
automatically.

One option is to *shard* the first part of the `UNION` to match the second
part:

```sql Re-shard Example theme={null}
SELECT
	manager_id,
	COUNT(*),
	KI_SHARD_KEY(manager_id)
FROM example.employee
GROUP BY manager_id
UNION
SELECT
	id,
	0,
	KI_MATCH_COLUMN(0)
FROM example.employee
WHERE id NOT IN
	(
		SELECT manager_id
		FROM example.employee
		WHERE manager_id IS NOT NULL
	)
```

Here, the *distribution function* `KI_SHARD_KEY` is used to make the selected
`manager_id` column the new *shard key* for the first part of the `UNION`.
Now, the *shard key* for the first part of the `UNION` (`manager_id`) aligns
with the *shard key* for the second part (`id`), and the query succeeds.  Note
the use of `KI_MATCH_COLUMN`, which aligns the selected column lists on each
side of the `UNION`.  Without this matching *distribution function*, the
`UNION` would appear to be merging three columns from the first part of the
query into two columns in the second part and would fail.

<Info>
  The `manager_id` column must exist in the `SELECT` list in order
  for the `KI_SHARD_KEY` function to designate it as the *shard key*.
</Info>

## Predicates

*Predicate* are generally used within a SQL `WHERE` clause to query records.
They compare the values of two or more *expressions*; whenever a record meets
the criteria defined in a *predicate clause* it will be marked as eligible
to be part of the query result set.  If it meets all *predicate clauses* defined
within a query, it will be returned in the result set.

A single *predicate clause* may use a simple *predicate operator* to compare the
values of two *expressions* or a more complex *predicate clause* form.  A
*compound predicate clause* uses a *compound predicate operator* to link
together multiple *predicate clauses* to further refine a result set.

Unlimited-width ([non-charN](/content/concepts/types#types-chart)) strings can only be used within
equality-based predicates, e.g. `=`, `IN`, etc.

<a id="sql-pred-op" />

### Predicate Operators

* `=` *equality*
* `!=` or `<>` *inequality*
* `<` *less than*
* `<=` *less than or equal to*
* `>` *greater than*
* `>=` *greater than or equal to*

### Predicate Clauses

In the following list of *predicate clauses*, `ref_expr` is the reference
expression to apply the predicate to; note that `EXISTS` has no reference
expression.

| Predicate Clause                                       | Description                                                                                                                                                                                                                     |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `<expr_a> <pred_op> <expr_b>`                          | Matches records where `expr_a` relates to `expr_b` according to [predicate operator](/content/sql/query#sql-pred-op) `pred_op`.                                                                                                 |
| `<ref_expr> <pred_op> ALL (<select statement>)`        | Matches records where the reference expression `ref_expr` relates to *all* of the results of `select statement` according to the [predicate operator](/content/sql/query#sql-pred-op) `pred_op`                                 |
| `<ref_expr> <pred_op> ANY (<select statement>)`        | Matches records where the reference expression `ref_expr` relates to *any* of the results of `select statement` according to the [predicate operator](/content/sql/query#sql-pred-op) `pred_op`                                 |
| `<ref_expr> [NOT] BETWEEN <begin_expr> AND <end_expr>` | Matches records where the reference expression `ref_expr` is (or is `NOT`) between the values of `begin_expr` and `end_expr`, inclusive                                                                                         |
| `<ref_expr> [NOT] IN (<match_list>)`                   | Matches records where the reference expression `ref_expr` is (or is `NOT`) in the `match_list` list of match values.  The list can either be a comma-separated list of terms/expressions or the result of a `SELECT` statement. |
| `<ref_expr> IS [NOT] NULL`                             | Matches records where the reference expression `ref_expr` is (or is `NOT`) *null*.                                                                                                                                              |
| `[NOT] EXISTS (<select statement>)`                    | Matches records where `select statement` returns 1 or more records.                                                                                                                                                             |

### Compound Predicate Operators

| Predicate Operator      | Description                                                 |
| ----------------------- | ----------------------------------------------------------- |
| `<pred_a> AND <pred_b>` | Matches records where both `pred_a` & `pred_b` are *true*   |
| `<pred_a> OR <pred_b>`  | Matches records where either `pred_a` or `pred_b` is *true* |
| `NOT <pred_b>`          | Matches records where `pred` is *false*                     |

## Subqueries

### Non-Correlated Subqueries

These are subqueries that are self-contained, in that they can be executed
independently of the surrounding query.

```sql Non-Correlated Subquery in SELECT Example theme={null}
SELECT
    last_name,
    first_name,
    sal,
    (
        SELECT AVG(sal)
        FROM example.employee
    ) AS avg_emp_sal
FROM example.employee
```

```sql Non-Correlated Subquery in FROM Example theme={null}
SELECT
    l || ', ' || f AS "Employee_Name"
FROM
    (
        SELECT last_name AS l, first_name AS f
        FROM example.employee
    )
```

```sql Non-Correlated Subquery in WHERE Example theme={null}
SELECT last_name, first_name
FROM example.employee
WHERE dept_id IN
    (
        SELECT id
        FROM example.department
        WHERE code = 'ENGR' OR code = 'MKTG'
    )
```

### Correlated Subqueries

These are subqueries that depend on the values in the surrounding query, and
cannot be executed independently of the surrounding query.

```sql Correlated Subquery Example theme={null}
SELECT *
FROM demo.nyctaxi o
WHERE fare_amount =
    (
        SELECT MAX(fare_amount)
        FROM demo.nyctaxi i
        WHERE o.passenger_count = i.passenger_count
    )
```

<Note>
  Correlated subqueries have the following limitations:

  * They cannot reference grouping columns in the parent query
  * They cannot reference tables beyond the immediate outer query; i.e., a
    table cannot be referenced in a correlated subquery that is two or more
    levels of nesting deeper than it is
  * They cannot contain disjunctive conditions
  * They cannot be part of an `OUTER JOIN ON` clause condition
</Note>

## Remote Queries

A *remote query* makes use of a
[data source](/content/sql/ddl#sql-create-data-source) to run a given query on the
remote system referenced by that *data source*.

```sql title="Remote Query Syntax" theme={null}
SELECT * FROM TABLE
(
	EXECUTE_REMOTE_QUERY
	(
		QUERY => '<remote query>',
		OPTIONS => KV_PAIRS(datasource_name = '<data source name>')
	)
)
```

### Parameters

<AccordionGroup>
  <Accordion title="<remote query>" id="<remote-query>" defaultOpen>
    SQL query to execute on the remote system.
  </Accordion>

  <Accordion title="<data source name>" id="<data-source-name>" defaultOpen>
    Name of the [data source](/content/sql/ddl#sql-create-data-source) referencing the remote system on
    which the query should be executed.
  </Accordion>
</AccordionGroup>

### Examples

To query employees' managers from a given remote system:

```sql Remote Query Example theme={null}
SELECT * FROM TABLE
(
	EXECUTE_REMOTE_QUERY
	(
		QUERY => '
			SELECT
			    e.last_name || '', '' || e.first_name AS "Employee_Name",
			    m.last_name || '', '' || m.first_name AS "Manager_Name"
			FROM
			    example.employee e
			    LEFT JOIN example.employee m ON e.manager_id = m.id
			WHERE
			    e.dept_id IN (1, 2, 3)
			ORDER BY
			    m.id ASC NULLS FIRST,
			    e.hire_date
		',
		OPTIONS => KV_PAIRS(datasource_name = 'example.jdbc_ds')
	)
)
```

To query employees' information from a given remote system and join it to data
in the host system:

```sql Remote/Local JOIN Query Example theme={null}
SELECT
    e.last_name || ', ' || e.first_name AS "Employee_Name",
    d.code
FROM
	TABLE
	(
		EXECUTE_REMOTE_QUERY
		(
			QUERY => '
				SELECT last_name, first_name, dept_id
				FROM example.employee
			',
			OPTIONS => KV_PAIRS(datasource_name = 'example.jdbc_ds')
		)
	) e,
	example.department d
WHERE e.dept_id = d.id
ORDER BY 1
```

<a id="sql-hints" />

## Hints

Hints can be added as comments within queries, and affect just the query in
which they appear.  They will override the corresponding client & server
settings (when such settings exist).

Kinetica supports both global & scoped hints:

* [Scoped Hints](/content/sql/query#sql-hints-scoped) - affect a portion of the query
* [Global Hints](/content/sql/query#sql-hints-global) - affect the entire query

<a id="sql-hints-scoped" />

### Scoped Hints

Scoped hints may appear anywhere in the query.  Scoped hints must be in a
comment block in the form:

```
/*+ <HINT>[,<HINT>...] */
```

```sql Scoped Hint Example theme={null}
CREATE MATERIALIZED VIEW example.weather_zone AS
SELECT w.name AS event_name, w.type AS event_type, gz.name AS zone
FROM example.weather /*+ KI_HINT_DELTA_TABLE */ w
JOIN example.geo_zone gz ON STXY_INTERSECTS(lon, lat, zone)
```

<AccordionGroup>
  <Accordion title="KI_HINT_DELTA_TABLE" id="ki_hint_delta_table" defaultOpen>
    Designates the corresponding table as a
    [delta table](/content/sql/ddl#sql-create-materialized-view-delta), within the
    context of a [CREATE MATERIALIZED VIEW](/content/sql/ddl#sql-create-materialized-view) statement.

    This hint must be placed immediately after the `FROM <table>` clause to
    which it applies, but before any table alias specified for that table.
  </Accordion>

  <Accordion title="KI_HINT_GROUP_BY_PK" id="ki_hint_group_by_pk" defaultOpen>
    Create primary keys for this [GROUP BY](/content/sql/query#sql-aggregation) result
    set on the grouped-upon columns/expressions; often used to create a
    [primary key](/content/concepts/tables#primary-key) on the result of a
    [CREATE TABLE ... AS](/content/sql/ddl#sql-create-table-as) that ends in a
    `GROUP BY`, and can also make
    [materialized views](/content/sql/ddl#sql-create-materialized-view) containing
    grouping operations more performant.

    <Info>
      If any of the grouped-on expressions are nullable, no
      primary key will be applied.
    </Info>

    This hint may be placed either immediately after the `SELECT`
    keyword or immediately after the `FROM <table>` clause.
  </Accordion>

  <Accordion title="KI_HINT_MATERIALIZE" id="ki_hint_materialize" defaultOpen>
    This can make some operations more performant, but can use more memory.  It
    would normally be used on a multi-dimensional [join](/content/sql/query#sql-join) or
    [union](/content/sql/query#sql-union) result set to speed up operations done on that
    result set.  This can also be used on a query with a
    [CTE](/content/sql/query#sql-cte) in the `WITH` clause; if different `WHERE`
    clauses are applied to the CTE, the CTE query may only have to be evaluated
    once.

    This hint must be placed immediately after the `SELECT` keyword, like the
    `SELECT` producing a join.

    <Info>
      `KI_HINT_MATERIALIZE` includes the functionality of
      `KI_HINT_NO_VIRTUAL_UNION`.
    </Info>
  </Accordion>

  <Accordion title="KI_HINT_NO_VIRTUAL_UNION" id="ki_hint_no_virtual_union" defaultOpen>
    This can make some operations more performant, but can use more memory.
    This would normally be used on a union query combining many tables or
    sub-queries.

    This scoped must be placed immediately after the `SELECT` keyword, like
    the first `SELECT` keyword in the union.
  </Accordion>
</AccordionGroup>

<a id="sql-hints-global" />

### Global Hints

Global hints may appear anywhere in the query.  Global hints must be in a
comment block in the form:

```
/* <HINT>[,<HINT>...] */
```

```sql Global Hint Example theme={null}
CREATE TABLE example.taxi_trip_daily_totals AS
/* KI_HINT_GROUP_BY_PK, KI_HINT_INDEX(transaction_date) */
SELECT vendor_id, DATE(dropoff_datetime) AS transaction_date, COUNT(*) AS total_trips
FROM demo.nyctaxi
GROUP BY vendor_id, transaction_date
```

<AccordionGroup>
  <Accordion title="KI_HINT_BATCH_SIZE(n)" id="ki_hint_batch_size-n" defaultOpen>
    Use an ingest batch size of `n` records.  Default: 10,000.

    Only applicable when issuing [INSERT](/content/sql/dml#sql-insert) statements.
  </Accordion>

  <Accordion title="KI_HINT_CHUNK_SIZE(n)" id="ki_hint_chunk_size-n" defaultOpen>
    Use chunk sizes of `n` records per chunk within result sets.
    Suffixes of `K` & `M` can be used to represent thousands or
    millions of records; e.g., `20K`, `50M`.
  </Accordion>

  <Accordion title="KI_HINT_COST_BASED_OPTIMIZATION" id="ki_hint_cost_based_optimization" defaultOpen>
    Cost-based optimizations are usually turned on by default.  If they have
    been turned off by default using a global configuration setting
    (`sql.cost_based_optimization`), they can be turned on for an individual
    query using this hint.
  </Accordion>

  <Accordion title="KI_HINT_DICT_PROJECTION" id="ki_hint_dict_projection" defaultOpen>
    Retain the [dictionary encoding](/content/concepts/dictionary_encoding)
    attributes of source columns in a projection result set.
  </Accordion>

  <Accordion title="KI_HINT_DISTRIBUTED_OPERATIONS" id="ki_hint_distributed_operations" defaultOpen>
    Reshard data when doing so would be the only way to process one or
    more operations in this query.
  </Accordion>

  <Accordion title="KI_HINT_DONT_COMBINE" id="ki_hint_dont_combine" defaultOpen>
    Don't combine joins and unions for this query.
  </Accordion>

  <Accordion title="KI_HINT_GROUP_BY_FORCE_REPLICATED" id="ki_hint_group_by_force_replicated" defaultOpen>
    Make all result tables within a single query replicated; useful when
    meeting the input table requirements of [JOIN](/content/sql/query#sql-join),
    [UNION](/content/sql/query#sql-union), etc. in a query containing aggregated
    subqueries which generate differently-sharded result tables.
  </Accordion>

  <Accordion title="KI_HINT_GROUP_BY_PK" id="ki_hint_group_by_pk-2" defaultOpen>
    Create primary keys for all [GROUP BY](/content/sql/query#sql-aggregation) result
    sets on the grouped-upon columns/expressions within a given query; often
    used to create a primary key on the result of a
    [CREATE TABLE ... AS](/content/sql/ddl#sql-create-table-as) that ends in a
    `GROUP BY`, and can also make materialized views containing grouping
    operations more performant.

    <Info>
      If any of the grouped-on expressions are nullable, no
      primary key will be applied.
    </Info>
  </Accordion>

  <Accordion title="KI_HINT_HAS_HEADER" id="ki_hint_has_header" defaultOpen>
    Assume the first line of the source CSV file has a header row.
    Only used with CSV ingestion via [INSERT INTO ... SELECT ... FROM FILE](/content/sql/load#sql-load-file-client).
  </Accordion>

  <Accordion title="KI_HINT_IGNORE_EXISTING_PK" id="ki_hint_ignore_existing_pk" defaultOpen>
    When inserting into or updating a table with a primary key, if the
    [INSERT](/content/sql/dml#sql-insert) or [UPDATE](/content/sql/dml#sql-update) results in a
    primary key collision, reject the command with no error or warning.  If the
    specified table does not have a primary key or the
    `KI_HINT_UPDATE_ON_EXISTING_PK` hint is used to switch to *upsert* mode
    for inserts or overwrite mode for updates, then this hint is ignored.
  </Accordion>

  <Accordion title="KI_HINT_INDEX(column_list)" id="ki_hint_index-column_list" defaultOpen>
    Create an index on each of the comma-separated columns in the given
    `column_list`; often used with
    [CREATE TABLE ... AS](/content/sql/ddl#sql-create-table-as) to create an index on a
    persisted result set.
  </Accordion>

  <Accordion title="KI_HINT_JOIN_TABLE_CHUNK_SIZE(n)" id="ki_hint_join_table_chunk_size-n" defaultOpen>
    Use chunk sizes of `n` records per chunk within joins.
    Suffixes of `K` & `M` can be used to represent thousands or
    millions of records; e.g., `20K`, `50M`.
  </Accordion>

  <Accordion title="KI_HINT_KEEP_TEMP_TABLES" id="ki_hint_keep_temp_tables" defaultOpen>
    Don't erase temp tables created by this query.
  </Accordion>

  <Accordion title="KI_HINT_KEY_LOOKUP" id="ki_hint_key_lookup" defaultOpen>
    Use [distributed key lookup](/content/tuning/multihead/multihead_egress) to
    retrieve records from a single table using a fast, indexed lookup.

    See [SQL](/content/tuning/multihead/multihead_egress#multi-head-egress-sql) for details and examples.
  </Accordion>

  <Accordion title="KI_HINT_NO_COST_BASED_OPTIMIZATION" id="ki_hint_no_cost_based_optimization" defaultOpen>
    Don't use the cost-based optimizer when calculating the query plan.
  </Accordion>

  <Accordion title="KI_HINT_NO_DICT_PROJECTION" id="ki_hint_no_dict_projection" defaultOpen>
    Don't retain [dictionary encoding](/content/concepts/dictionary_encoding)
    attributes of source columns in a projection result set.
  </Accordion>

  <Accordion title="KI_HINT_NO_DISTRIBUTED_OPERATIONS" id="ki_hint_no_distributed_operations" defaultOpen>
    Don't reshard data when doing so would be the only way to process
    one or more operations in this query.
  </Accordion>

  <Accordion title="KI_HINT_NO_HEADER" id="ki_hint_no_header" defaultOpen>
    Assume the source CSV file has no header row.  Only used
    with CSV ingestion via [INSERT INTO ... SELECT ... FROM FILE](/content/sql/load#sql-load-file-client).
  </Accordion>

  <Accordion title="KI_HINT_NO_JOIN_COUNT" id="ki_hint_no_join_count" defaultOpen>
    Optimize joins by not calculating intermediate set counts.
  </Accordion>

  <Accordion title="KI_HINT_NO_LATE_MATERIALIZATION" id="ki_hint_no_late_materialization" defaultOpen>
    Force the materialization of intermediary result sets.
  </Accordion>

  <Accordion title="KI_HINT_NO_NATIVE_SEMI_JOINS" id="ki_hint_no_native_semi_joins" defaultOpen>
    Don't use semi-joins.
  </Accordion>

  <Accordion title="KI_HINT_NO_PARALLEL_EXECUTION" id="ki_hint_no_parallel_execution" defaultOpen>
    Execute all components of this query in series.
  </Accordion>

  <Accordion title="KI_HINT_NO_PLAN_CACHE" id="ki_hint_no_plan_cache" defaultOpen>
    Don't cache the query plan calculated for this query.
  </Accordion>

  <Accordion title="KI_HINT_NO_QUERY_RESULT_CACHING" id="ki_hint_no_query_result_caching" defaultOpen>
    Don't use the query cache for processing this query.
  </Accordion>

  <Accordion title="KI_HINT_NO_RULE_BASED_OPTIMIZATION" id="ki_hint_no_rule_based_optimization" defaultOpen>
    Don't use the rule-based optimizer when calculating the query plan.
  </Accordion>

  <Accordion title="KI_HINT_NO_SHADOW_CUBE" id="ki_hint_no_shadow_cube" defaultOpen>
    Don't use the shadow cube for caching requests in the worker processes.
  </Accordion>

  <Accordion title="KI_HINT_NO_SSQ_OPTIMIZATION" id="ki_hint_no_ssq_optimization" defaultOpen>
    Don't optimize the query using Scalar Sub-Query (SSQ) substitution.
  </Accordion>

  <Accordion title="KI_HINT_NO_VALIDATE_CHANGE" id="ki_hint_no_validate_change" defaultOpen>
    Don't fail an [ALTER TABLE](/content/sql/ddl#sql-alter-table) command when changing
    column types/sizes and the column data is too long/large.  Truncate the
    data instead and allow the modification to succeed.
  </Accordion>

  <Accordion title="KI_HINT_NO_VIRTUAL_UNION" id="ki_hint_no_virtual_union-2" defaultOpen>
    Don't utilize Virtual Unions when performing this query.
  </Accordion>

  <Accordion title="KI_HINT_PROJECT_MATERIALIZED_VIEW" id="ki_hint_project_materialized_view" defaultOpen>
    Force the materialization of a *materialized view*.  Some
    *materialized views* containing [JOIN](/content/sql/query#sql-join) clauses will be
    backed by a [native join view](/content/concepts/joins#join-native).  This is done to
    improve the performance of *materialized view* refreshes and reduce memory
    usage at the cost of reduced query performance.  This hint will induce the
    reverse of this trade-off -- increased query performance at the cost
    of reduced refresh performance and increased memory usage.
  </Accordion>

  <Accordion title="KI_HINT_REPL_ASYNC" id="ki_hint_repl_async" defaultOpen>
    Instruct the target database to treat this statement as one that
    should be run asynchronously and serially across all
    [high availability](/content/ha/ha_architecture) clusters in its ring.  See
    [HA Asynchronous Operation Handling](/content/ha/ha_architecture#ha-op-async) for details.

    <Info>
      The target database must be configured for
      high-availability for this to have an effect.  See
      [High Availability Configuration & Management](/content/ha/ha_configuration) for details.
    </Info>
  </Accordion>

  <Accordion title="KI_HINT_REPL_ASYNC_PARALLEL" id="ki_hint_repl_async_parallel" defaultOpen>
    Instruct the target database to treat this statement as one that
    should be run asynchronously and in parallel across all
    [high availability](/content/ha/ha_architecture) clusters in its ring.  See
    [HA Asynchronous Operation Handling](/content/ha/ha_architecture#ha-op-async) for details.

    <Info>
      The target database must be configured for
      high-availability for this to have an effect.  See
      [High Availability Configuration & Management](/content/ha/ha_configuration) for details.
    </Info>
  </Accordion>

  <Accordion title="KI_HINT_REPL_NONE" id="ki_hint_repl_none" defaultOpen>
    Instruct the target database to treat this statement as one that should not
    be run across all [high availability](/content/ha/ha_architecture) clusters
    in its ring. See [HA Query Operation Handling](/content/ha/ha_architecture#ha-op-query) for
    details.

    <Info>
      The target database must be configured for
      high-availability for this to have an effect.  See
      [High Availability Configuration & Management](/content/ha/ha_configuration) for details.
    </Info>
  </Accordion>

  <Accordion title="KI_HINT_REPL_SYNC" id="ki_hint_repl_sync" defaultOpen>
    Instruct the target database to treat this statement as one that
    should be run synchronously and serially across all
    [high availability](/content/ha/ha_architecture) clusters in its ring.  See
    [HA Synchronous Operation Handling](/content/ha/ha_architecture#ha-op-sync) for details.

    <Info>
      The target database must be configured for
      high-availability for this to have an effect.  See
      [High Availability Configuration & Management](/content/ha/ha_configuration) for details.
    </Info>
  </Accordion>

  <Accordion title="KI_HINT_REPL_SYNC_PARALLEL" id="ki_hint_repl_sync_parallel" defaultOpen>
    Instruct the target database to treat this statement as one that
    should be run synchronously and in parallel across all
    [high availability](/content/ha/ha_architecture) clusters in its ring.  See
    [HA Synchronous Operation Handling](/content/ha/ha_architecture#ha-op-sync) for details.

    <Info>
      The target database must be configured for
      high-availability for this to have an effect.  See
      [High Availability Configuration & Management](/content/ha/ha_configuration) for details.
    </Info>
  </Accordion>

  <Accordion title="KI_HINT_REQUEST_TIMEOUT(m)" id="ki_hint_request_timeout-m" defaultOpen>
    Use a timeout of `m` minutes when processing this command.
  </Accordion>

  <Accordion title="KI_HINT_SAVE_UDF_STATS" id="ki_hint_save_udf_stats" defaultOpen>
    Save statistics of UDF runs for UDFs invoked via SQL.
  </Accordion>

  <Accordion title="KI_HINT_SERVER_SIDE_INSERT" id="ki_hint_server_side_insert" defaultOpen>
    Issue the [INSERT INTO ... VALUE](/content/sql/dml#sql-insert-values) statement as
    a server-side command, instead of incurring the overhead of the client-side
    distributed ingestion processor, which can give better performance when
    inserting many rows.
  </Accordion>

  <Accordion title="KI_HINT_TRUNCATE_STRINGS" id="ki_hint_truncate_strings" defaultOpen>
    Truncate all strings being inserted into restricted-width *(charN)*
    columns to the max width for the column.  Used with any
    [INSERT INTO](/content/sql/dml#sql-insert), [LOAD INTO](/content/sql/load#sql-load-into), or
    [CREATE EXTERNAL TABLE](/content/sql/ddl#sql-create-ext-table) statement.
  </Accordion>

  <Accordion title="KI_HINT_UPDATE_ON_EXISTING_PK" id="ki_hint_update_on_existing_pk" defaultOpen>
    Change the record collision policy for inserting into or updating a table
    with a primary key:

    * For [INSERT](/content/sql/dml#sql-insert) statements, invoke an *upsert* scheme;
      any existing table record with primary key values that match those of a
      record being inserted will be replaced by that new record.
    * For [UPDATE](/content/sql/dml#sql-update) statements, invoke an overwrite scheme;
      if a record update causes the record's primary key to match that of
      another record in the same table, that other record will be removed and
      the original record will remain, updated with its new primary key and any
      other values from the `SET` clause.

    Without this hint, the `INSERT` or `UPDATE` will be rejected and the
    error handled based on the presence of the `KI_HINT_IGNORE_EXISTING_PK`
    hint.  If the specified table does not have a primary key, then this hint
    will be ignored.
  </Accordion>

  <Accordion title="KI_HINT_WAL_SYNC_METHOD(method)" id="ki_hint_wal_sync_method-method" defaultOpen>
    Specify the WAL sync `method` for a query.

    <div>
      <table class="table w-full [&_td]:min-w-[150px] [&_th]:text-left [&_td[data-numeric]]:tabular-nums">
        <thead>
          <tr>
            <th>Method</th>
            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td><code>none</code></td>
            <td>Disables the write-ahead log feature.</td>
          </tr>

          <tr>
            <td><code>background</code></td>
            <td>WAL entries are periodically written instead of immediately after each operation.</td>
          </tr>

          <tr>
            <td><code>flush</code></td>
            <td>Protects entries in the event of a database crash.</td>
          </tr>

          <tr>
            <td><code>fsync</code></td>
            <td>Protects entries in the event of an OS crash.</td>
          </tr>
        </tbody>
      </table>
    </div>
  </Accordion>
</AccordionGroup>

#### Testing Hints

The following global hints are intended to be used for testing.
They are usually not recommended for regular use and are subject to change.

<AccordionGroup>
  <Accordion title="KI_HINT_NO_CHUNK_SKIPPING" id="ki_hint_no_chunk_skipping" defaultOpen>
    Do not use any chunk-skipping optimizations when performing this query.
    Currently, this only affects chunk-skipping performed in join operations.
  </Accordion>

  <Accordion title="KI_HINT_NO_CONSTANT_FOLDING" id="ki_hint_no_constant_folding" defaultOpen>
    Do not use constant-folding optimizations when performing this query.
  </Accordion>

  <Accordion title="KI_HINT_NO_HAVING_PUSHDOWN" id="ki_hint_no_having_pushdown" defaultOpen>
    Do not push down any `HAVING` clauses when planning this query.
  </Accordion>

  <Accordion title="KI_HINT_NO_TRANSITIVE_SIMPLIFICATIONS" id="ki_hint_no_transitive_simplifications" defaultOpen>
    Normally, if a query contains "x = y" and "x = 5" then the transitive
    simplification will add "y = 5" in some cases.  This usually helps perform
    optimizations.  This hint disables this behavior.
  </Accordion>
</AccordionGroup>

<a id="sql-explain" />

## EXPLAIN

Outputs the execution plan of a given SQL statement.

<Tip>
  For the visual explain plan utility in *GAdmin*, see the *Explain*
  feature under [SQL Tool](/content/admin/gadmin/query#gadmin-sql).
</Tip>

```sql title="EXPLAIN Syntax" theme={null}
EXPLAIN [PHYSICAL|ANALYZE|VERBOSE|VERBOSE ANALYZE] [FORMAT <JSON|TABLE>] <statement>
```

Each supporting API endpoint call that is made in servicing the request is
listed as an execution plan step in the output, along with any input or output
tables associated with the call and the prior plan execution steps on which a
given execution step depends.

The following options can be specified:

* `PHYSICAL` - *(default)* outputs the physical execution plan with the
  following endpoint-level details per step:

  * `ID` - execution step number
  * `ENDPOINT` - name of native API endpoint called
  * `INPUT_TABLES` - input tables used by the endpoint *(if any)*
  * `OUTPUT_TABLE` - output table created by the endpoint *(if any)*
  * `DEPENDENCIES` - list of prior execution steps upon which this step
    depends

* `ANALYZE` - same as `PHYSICAL`, including additional run-time details:

  * `RUN_TIME` - execution time of each endpoint call
  * `RESULT_ROWS` - number of records produced in the endpoint call

* `VERBOSE` - same as `PHYSICAL`, including endpoint parameter details:

  * `COLUMNS` - columns passed to the endpoint call
  * `EXPRESSIONS` - expressions passed to the endpoint call
  * `OPTIONS` - option keys & values passed to the endpoint call
  * `LAST_USE_TABLES` - list of tables that will not be used by any following
    execution step
  * `ADDITIONAL_INFO` - other parameters passed to the endpoint call

* `VERBOSE ANALYZE` - same as `VERBOSE` & `ANALYZE` together, including
  the execution plan for any joins contained within the query

* `FORMAT JSON` - outputs the result in JSON format

* `FORMAT TABLE` - *(default)* outputs the result in tabular format

<Tip>
  For `PHYSICAL` & `VERBOSE` modes, the
  `/* KI_HINT_RECURSIVE_EXPLAIN */` hint can be used to show the plan
  recursively through any materialized views involved in the query.
</Tip>

<Note>
  Specifying `ANALYZE` will cause the statement to be executed
  in order to collect run-time statistics on the endpoint calls made.
</Note>

For example, to output the execution plan for a query that aggregates the number
of taxi rides between boroughs:

```sql EXPLAIN Example theme={null}
EXPLAIN
SELECT
    n_begin.ntaname AS boro_begin,
    boro_end,
    COUNT(*) AS total_trips
FROM
(
    SELECT pickup_latitude, pickup_longitude, n_end.ntaname AS boro_end
    FROM demo.nyctaxi t
    JOIN example_geospatial.nyc_neighborhood n_end ON STXY_INTERSECTS(dropoff_longitude, dropoff_latitude, geom)
)
JOIN example_geospatial.nyc_neighborhood n_begin ON STXY_INTERSECTS(pickup_longitude, pickup_latitude, geom)
GROUP BY 1, 2
```

The execution plan is listed in table format, as follows:

```sql EXPLAIN Output theme={null}
+------+-------------------------+----------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------+----------------+
| ID   | ENDPOINT                | INPUT_TABLES                                                                                                                     | OUTPUT_TABLE                                                           | DEPENDENCIES   |
+------+-------------------------+----------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------+----------------+
| 0    | /create/jointable       | demo.nyctaxi AS TableAlias_0_,example_geospatial.nyc_neighborhood AS TableAlias_1_                                               | sys_sql_temp.Join_3_01234567_89ab_cdef_0123_456789abcdef               | -1             |
| 1    | /create/jointable       | sys_sql_temp.Join_3_01234567_89ab_cdef_0123_456789abcdef AS TableAlias_0_,example_geospatial.nyc_neighborhood AS TableAlias_1_   | sys_sql_temp.Join_5_01234567_89ab_cdef_0123_456789abcdef               | 0              |
| 2    | /aggregate/groupby      | sys_sql_temp.Join_5_01234567_89ab_cdef_0123_456789abcdef                                                                         | sys_sql_temp.ShardedAggregate_7_01234567_89ab_cdef_0123_456789abcdef   | 1              |
| 3    | /get/records/bycolumn   | sys_sql_temp.ShardedAggregate_7_01234567_89ab_cdef_0123_456789abcdef                                                             |                                                                        | 2              |
+------+-------------------------+----------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------+----------------+
```

If there is an error processing a query, the error can be returned in the
JSON-formatted execution plan:

```sql EXPLAIN with Detail Example theme={null}
EXPLAIN VERBOSE ANALYZE FORMAT JSON
SELECT * /* KI_HINT_NO_DISTRIBUTED_OPERATIONS */
FROM example.explain_table t1
JOIN example.explain_table t2 ON t1.shard_column = t2.not_shard_column
```

The execution plan is listed in JSON format with the query error, as follows:

```EXPLAIN with Detail Output theme={null}
"PLAN": [
    {
        "ADDITIONAL_INFO": "Not all of the non-replicated tables are equated by shard keys. Number of sharded sets: 2, Number of components connected: 0 (<REF>)",
        "COLUMNS": "TableAlias_0_.shard_column AS shard_column,TableAlias_0_.not_shard_column AS not_shard_column,TableAlias_1_.shard_column AS shard_column0,TableAlias_1_.not_shard_column AS not_shard_column0",
        "DEPENDENCIES": "-1",
        "ENDPOINT": "/create/jointable",
        "EXPRESSIONS": "inner join TableAlias_0_, TableAlias_1_  on   (TableAlias_0_.shard_column = TableAlias_1_.not_shard_column )  ",
        "ID": "0",
        "INFO": "{"estimate_input_row_counts":"1.0, 1.0","estimate_row_count":"1.0"}",
        "JSON_REQUEST": "{
            "join_table_name": "<sys_sql_temp.>Join_1_01234567_89ab_cdef_0123_456789abcdef",
            "table_names": [
                "example.explain_table AS TableAlias_0_",
                "example.explain_table AS TableAlias_1_"
            ],
            "column_names": [
                "TableAlias_0_.shard_column AS shard_column",
                "TableAlias_0_.not_shard_column AS not_shard_column",
                "TableAlias_1_.shard_column AS shard_column0",
                "TableAlias_1_.not_shard_column AS not_shard_column0"
            ],
            "expressions": [
                "inner join TableAlias_0_, TableAlias_1_  on   (TableAlias_0_.shard_column = TableAlias_1_.not_shard_column )  "
            ],
            "options": {
                "create_explain": "true",
                "show_filters": "true",
                "ttl": "-1"
            }
        }",
        "LAST_USE_TABLES": "",
        "OPTIONS": "{create_explain,true} {show_filters,true} {ttl,-1}",
        "RESULT_DISTRIBUTION": "NA / ;",
        "RESULT_ROWS": "0",
        "RUN_TIME": "0",
        "TABLE_DEFINITIONS": "CREATE TABLE "example"."explain_table"\r
        (\r
            "shard_column" INTEGER (shard_key),\r
            "not_shard_column" INTEGER\r
        )\r
        TIER STRATEGY (\r
            ( ( VRAM 1, RAM 5, DISK0 5, PERSIST 5 ) )\r
        );
        CREATE TABLE "example"."explain_table"\r
        (\r
            "shard_column" INTEGER (shard_key),\r
            "not_shard_column" INTEGER\r
        )\r
        TIER STRATEGY (\r
            ( ( VRAM 1, RAM 5, DISK0 5, PERSIST 5 ) )\r
        );"
    },
    {
        "ADDITIONAL_INFO": "",
        "COLUMNS": "shard_column AS shard_column, not_shard_column AS not_shard_column, shard_column0 AS shard_column0, not_shard_column0 AS not_shard_column0",
        "DEPENDENCIES": "0",
        "ENDPOINT": "/get/records/bycolumn",
        "EXPRESSIONS": "",
        "ID": "1",
        "INFO": "",
        "JSON_REQUEST": "{
            "table_name": "sys_sql_temp.Join_1_01234567_89ab_cdef_0123_456789abcdef",
            "column_names": [
                "shard_column AS shard_column",
                "not_shard_column AS not_shard_column",
                "shard_column0 AS shard_column0",
                "not_shard_column0 AS not_shard_column0"
            ],
            "offset": 0,
            "limit": -9999,
            "encoding": "binary",
            "options": {}
        }",
        "LAST_USE_TABLES": "<sys_sql_temp.>Join_1_01234567_89ab_cdef_0123_456789abcdef",
        "OPTIONS": "",
        "RESULT_DISTRIBUTION": "",
        "RESULT_ROWS": "0",
        "RUN_TIME": "0",
        "TABLE_DEFINITIONS": ""
    }
]
```
