# Row Expression Comparison

Pinot supports implicit row-style comparisons in multi-stage queries. These comparisons are useful for keyset pagination and other lexicographic comparisons across multiple columns.

Pinot does not materialize a row type at runtime. Instead, it rewrites the comparison during planning using the same lexicographic semantics described in the [jOOQ row-value comparison transformations](https://www.jooq.org/doc/latest/manual/sql-building/conditional-expressions/comparison-predicate-degree-n/).

## Supported syntax

Use a parenthesized list of expressions on both sides of one of the supported comparison operators:

```sql
WHERE (col1, col2, col3) > (val1, val2, val3)
```

Supported comparison operators:

```
=, <>, <, <=, >, >=
```

{% hint style="info" %}
Explicit `ROW()` syntax is not supported. Use implicit parenthesized expressions such as `(col1, col2) > (1, 2)` instead of `ROW(col1, col2) > ROW(1, 2)`.
{% endhint %}

## Validation rules

Pinot validates row-style comparisons before planning the query:

* Both sides of the comparison must be row expressions.
* Both row expressions must have the same number of fields.
* Row expressions cannot be empty.
* Row expressions are only supported in comparison predicates.

If any of these checks fail, Pinot rejects the query during validation.

## Supported contexts

Row-style comparisons are supported in comparison predicates, including:

* `WHERE` clauses
* comparison predicates inside subqueries
* comparison predicates inside CTEs

Examples:

```sql
SELECT COUNT(*)
FROM myTable
WHERE (airTime, actualElapsedTime) > (200, 230)
```

```sql
SELECT airlineId, carrier, airTime
FROM myTable
WHERE (airlineId, carrier, airTime) > (20000, 'AA', 120)
ORDER BY airlineId, carrier, airTime
LIMIT 10
```

```sql
WITH filtered AS (
  SELECT airlineId, carrier, airTime
  FROM myTable
  WHERE airlineId > 19000
)
SELECT COUNT(*)
FROM filtered
WHERE (airlineId, carrier) > (20000, 'AA')
```

## Unsupported contexts

Row expressions are rejected outside comparison predicates. In particular, they are not supported in:

* `SELECT` lists
* `GROUP BY`
* `ORDER BY`
* function arguments

Examples that Pinot rejects:

```sql
SELECT (airTime, actualElapsedTime) FROM myTable
```

```sql
SELECT COUNT(*) FROM myTable GROUP BY (airlineId, carrier)
```

```sql
SELECT airlineId, carrier FROM myTable ORDER BY (airlineId, carrier)
```

## Semantics

Row comparisons are lexicographic, not element-wise. For example:

```sql
WHERE (a, b, c) > (x, y, z)
```

is equivalent to:

```sql
WHERE a > x
   OR (a = x AND b > y)
   OR (a = x AND b = y AND c > z)
```

Likewise:

```sql
WHERE (a, b, c) = (x, y, z)
```

is equivalent to:

```sql
WHERE a = x
  AND b = y
  AND c = z
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.pinot.apache.org/build-with-pinot/querying-and-sql/sql-syntax/row-expression-comparison.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
