SQL best practices
Boards are built from widgets, and each widget is powered by a SQL query. The SQL dialect here is column-oriented and tuned for fast aggregations over large call datasets, so some of its functions and conventions differ from standard PostgreSQL or MySQL and may be new to you.
This page explains how to write and review the SQL behind a widget: where to write it, how to confirm the schema for your organization, which patterns to use, and how to generate a draft query with AI. For the surrounding UI flow, start at Boards and Create a widget.
The SQL editor
You write and run widget queries in the SQL editor. The following actions are available while editing:
Browse the schema
Before writing a query, open Schema to see the databases, tables, and column types available to your organization. Table and column names vary between organizations, so confirm them here rather than assuming names from documentation or from an AI suggestion. Using the exact names from Schema is the most common way to avoid a query that fails to run or returns no rows.
Read-only access
The editor allows read-style queries only. The following statements are blocked and underlined in the editor, and will not run:
DELETE · DROP · TRUNCATE · ALTER · INSERT · UPDATE
Write your widgets with SELECT. Common table expressions (CTEs) and subqueries are supported as long as they only read data.
Write efficient queries
Queries are fastest when you filter early and aggregate in the database rather than returning raw rows to the widget. The following steps produce queries that stay fast and map cleanly onto a chart.
Confirm the schema
Open Schema and use the exact table and column names for your organization. Do not invent names from documentation or from an AI draft.
Filter early
Push time and entity filters into the WHERE clause, ideally through board filter tokens so the widget stays reusable:
Frequently used patterns include toDate(...) and toStartOfHour(...) for time bucketing, countIf(condition) and avgIf(column, condition) for conditional aggregation, and ORDER BY ... DESC LIMIT 20 to return only the top results.
Generate SQL with AI
If you are new to this SQL dialect, you can describe the question in plain language and let Generate with AI produce a draft query for you to review.
Describe the question
State the metric in plain language, for example: average handle time per agent for the last 7 days.
Treat AI output as a starting point and confirm it before saving.
What AI is good for
- First drafts of aggregations and time series
- Rewrites after you change the question
- Helping teammates who are new to the SQL syntax
What you must still verify
- Table and column names against Schema
- Filter tokens (
{{filters}}) for reusable boards - Metric definitions (connected vs. attempted vs. engaged)
- Read-only access — blocked statements will not run
- Spot-checks against Agent Analytics when the metric overlaps
Before you save
Confirm each of the following before saving a widget query:
- The query is
SELECT-only and contains no blocked statements. - Time and entity filters use board filter tokens where you need control over operators.
- The result shape matches the widget type (Table, Number, Bar, or Line).
- Table and column names match the schema for your organization.
- Filter defaults are set so the board is not empty on first open. See Filters.
- The widget title describes the metric in plain language.