Skip to main content
This page catalogs the operators and functions available in Braintrust SQL queries. For clauses, data sources, and field access, see SQL query structure. For copy-and-run patterns, see Example queries.

SQL operators

Use these operators in WHERE, HAVING, SELECT, and other clauses.

Comparison operators

Null operators

Text-matching operators

For wildcard behavior and the 65KB limit, see Pattern matching. For MATCH and search(), see Full-text search.

Logical operators

Arithmetic operators

INCLUDES, NOT INCLUDES, and CONTAINS are BTQL-only operators and raise a syntax error in SQL mode. For exact array membership in SQL mode, use IN and NOT IN (e.g., tags IN ('value')). MATCH is a fuzzy approximation that tokenizes text, so tags MATCH 'value' also matches values containing the term as a token, such as value-added.

SQL functions

Use these functions in SELECT, WHERE, and GROUP BY clauses, and in aggregate measures.

Date and time functions

date_trunc accepts 'second', 'minute', 'hour', 'day', 'week', 'month', or 'year', or a positive integer multiple of second(s), minute(s), hour(s), or day(s) (for example, '15 minutes' or '2 hours'). The 'week', 'month', and 'year' intervals don’t accept multiples because they have variable durations.

String functions

Array functions

JSON functions

Use json_extract when a field’s value is a JSON-encoded string rather than a native object. For native object and array access, use field access instead. See Extract data from JSON strings for worked examples.

Null-handling functions

coalesce(field, 'x') != 'y' is automatically rewritten to field <!=> 'y' for better index performance.

Type conversion and cast functions

Search functions

search(query) is equivalent to writing input MATCH query OR output MATCH query OR ... for each text field. When log search optimization is enabled on the project, search() uses bloom filters to skip irrelevant segments automatically. Shingled search optimization extends this to multi-word and phrase queries. See Full-text search.

Cost functions

On the spans and traces shapes, estimated_cost() and metrics.estimated_cost are populated on LLM spans, not the root/task span. Filtering to is_root = true returns null cost. To get a trace’s total cost, sum across its spans with sum(estimated_cost()). The summary shape rolls this up per trace automatically.Valid component names for estimated_cost_breakdown() and estimated_cost_component(): promptUncachedTokensCost, promptCachedTokensCost, promptCacheCreationTokensCost (single-tier cache creation), promptCacheCreation5mTokensCost and promptCacheCreation1hTokensCost (two-tier cache creation, e.g. Anthropic), completionTokensCost, and totalCost.

Aggregate functions

Aggregate functions are available only in measures or with GROUP BY.

Conditional expressions

SQL supports conditional logic through CASE WHEN for multi-branch conditions, IF for two-branch conditions, and COUNT_IF for conditional aggregation.

CASE WHEN

Use CASE WHEN ... THEN ... ELSE ... END for one or more branches:

IF and COUNT_IF

For two-branch conditions, IF(condition, then_value, else_value) is a shorter alternative to CASE WHEN. Use CASE WHEN when you need more than two branches.
COUNT_IF(condition) counts rows where the condition is true. It is equivalent to count(CASE WHEN condition THEN 1 ELSE NULL END).
IF composes with other aggregates. For example, count distinct users who hit a condition:

Next steps