docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md
{{< docs/public-preview product="SQL expressions" >}}
SQL Expressions are server-side expressions that manipulate and transform the results of data source queries using MySQL-like syntax. They allow you to easily query and transform your data after it has been queried, using SQL, which provides a familiar and powerful syntax that can handle everything from simple filters to highly complex, multi-step transformations.
In Grafana, a server-side expression is a way to transform or calculate data after it has been retrieved from the data source, but before it is sent to the frontend for visualization. Grafana evaluates these expressions on the server, not in the browser or at the data source.
For general information on Grafana expressions, refer to Write expression queries.
sqlExpressions.
grafana.ini.[feature_toggles]
enable = sqlExpressions
SQL expressions allow you to:
A key capability of SQL expressions is the ability to JOIN data from multiple tables. This allows users to combine and transform data in a predictable, user-friendly way—even for complex use cases. You can JOIN data from an unlimited number of data source queries.
To work with SQL expressions, you must use data from a backend data source. In Grafana, a backend data source refers to a data source plugin or integration that communicates with a database, service, or API through the Grafana server, rather than directly from the browser (frontend).
The following are compatible data sources:
Full support: Grafana supports all query types for each of these data sources.
Partial support: The following data sources have limited or conditional support. Some support multiple query types depending on the service. For example, Azure Monitor can query multiple services, each with its own query format. In some cases, you can also switch the query type within a panel.
To create a SQL expression, complete the following steps:
After you have added a SQL expression, you can select from other data source queries by referencing the RefIDs of the queries in your SQL expression as if they were tables in a SQL database.
{{< admonition type="note" >}} The RefID is a unique identifier assigned to each query within a Grafana panel that serves as a reference name for that query's data. {{< /admonition >}}
Use the following workflow to create a SQL expression:
Build your base queries. Create the individual query and give it a meaningful name. Create the queries (A, B, etc.) that provide the data you want to combine or transform using SQL Expressions.
Hide your base queries. Click the 👁️ Eye icon next to each base query to hide them from visualization. This keeps your panel clean while still making the data available to the SQL Expression.
Switch to table view. Set the panel visualization to Table to inspect and review the structure and output of your SQL expression as you build and refine it.
Add a SQL Expression. Add a new query and add select SQL Expression as its type.
Inspect inputs. Start with simple test queries to understand the shape of your input frames.
SELECT * FROM A LIMIT 10
This lets you see the available columns and sample rows from query A. Repeat this for each input query you want to use (e.g., SELECT * FROM B LIMIT 10).
Inspect your data. Repeat this for each input query to understand the column structure and data types you're working with.
SELECT * FROM <B, C, D, etc> LIMIT 10
Construct the SQL expression. Once you understand your data, you can write your SQL expression to join, filter, or otherwise transform the data.
Validate and iterate. Click Refresh every time you update your SQL query to re-evaluate and see the updated result.
When selecting a visualization type, ensure your SQL expression returns data in the required shape. For example, time series panels require a column with a time field (e.g., timestamp) and a numeric value column (e.g., __value__). If the output is not shaped correctly, your visualization may appear empty or fail to render.
The SQL expression workflow in Grafana is designed with the following behaviors:
Unhidden queries are visualized automatically. If an input query is not hidden, Grafana will attempt to render it alongside your SQL expression. This can clutter the output, especially in table visualizations.
SQL expression results may not be immediately visible. You might need to use the data frame selector (dropdown at the bottom of the table panel) to switch between the raw query and the SQL expression result.
Non-tabular or incorrectly shaped data will not render in certain panels. Visualizations such as graphs or gauges require properly structured data. Mismatched formats will result in rendering issues or missing data.
When you reference a RefID within a SQL statement (e.g., SELECT * FROM A), the system invokes a distinct SQL conversion process.
The SQL conversion path:
Grafana maintains a complete list of supported SQL keywords, operators, and functions in the SQL expressions query validator implementation.
For the most up-to-date reference of all supported SQL functionality, refer to the allowedNode and allowedFunction definitions in the Grafana codebase.
SQL expressions integrates alerting and recording rules, allowing you to define complex conditions and metrics using standard SQL queries. The system processes your query results and automatically creates alert instances or recorded metrics based on the returned data structure.
For SQL Expressions to work properly with alerting and recording rules, your query must return:
service, region.Consider the following query results:
error_count,service,region
25,auth-service,us-east
0,payment-service,us-west
15,user-service,eu-west
This query returns:
error_count (values: 25, 0, 15)service and regionFor alert rules, this creates three alert instances:
For recording rules, creates one metric with three series:
Following are some best practices for alerting and recording rules:
GROUP BY to avoid duplicate label errors.SUM(error_count)).Grafana supports three types of data source response formats:
Single Table-like Frame:
This refers to data returned in a standard tabular structure, where all values are organized into rows and columns, similar to what you'd get from a SQL query.
Dataplane: Time Series Format:
This format represents time series data with timestamps and associated values. It is typically returned from monitoring data sources.
Dataplane: Numeric Long Format:
This format is used for point-in-time (instant) metric queries that return a single value (or a set of values) at a specific moment.
For more information on Dataplane formats, refer to Grafana Dataplane Documentation.
The following non-tabular formats are automatically converted to a tabular format (FullLong) when used in SQL expressions:
value column contains the numeric metric value.display_name column.During conversion:
value column contains the numeric metric.display_name column contains a human-readable name.metric_name column stores the raw metric identifier.time column with timestampssqlExpressionsColumnAutoComplete feature toggle, which is provided on an experimental basis.SQL expressions depend on a third-party SQL engine that uses cgo by default for full regular expression compatibility with MySQL. However, Grafana is built without cgo, which limits regular expression support.
SQL expressions that use regular expression functions have limitations such as:
\r) characters.There may be other minor differences as well.
For implementation context, refer to the go-mysql-server regular expression compatibility notes.
SQL expressions have known limitations that may cause queries to fail or return unexpected results. These constraints are inherent to how the feature is implemented and should be understood when building queries.
The following situations are affected:
Error responses – When a data source query returns an error, SQL expressions cannot interpret the result.
No data responses – If a query returns no rows, the SQL expression engine cannot infer a schema.
Dynamic schema responses – If the set of columns or labels changes between query executions, SQL expressions may fail because it treats column changes as schema changes.
SQL expressions are powered by an embedded SQL engine where each query result is treated as a table. The schema of that table is derived from the columns returned by the underlying data source.
Unlike traditional SQL databases, where schemas are usually fixed, many Grafana data sources (for example, Prometheus) can return results with varying label sets or no data at all.
When this happens:
As a result, SQL expressions can’t gracefully handle changes in schema or no-data conditions, since these cases violate the static schema model that SQL relies on.
You can mitigate these issues in the following ways:
Avoid SELECT * – Explicitly select only the columns you expect to exist.
Ensure a consistent schema – If possible, configure your query to always return columns, even when no data is present.
When joining results from the same Prometheus query across different data source instances, you can use this pattern:
-- Prometheus query
sum by (cluster) (up{job=~".*zruler.*"})
or on (cluster) (
(0/0) *
(
label_replace(vector(1), "cluster", "fake", "", "")
)
)
-- SQL expression
SELECT
COALESCE(a.time, b.time) AS time,
COALESCE(a.cluster, b.cluster) AS cluster,
COALESCE(a.up, 0) + COALESCE(b.up, 0) AS unified_up
FROM (
SELECT time, cluster, __value__ AS up
FROM A
WHERE cluster != 'fake'
ORDER BY time
LIMIT 5
) a
FULL OUTER JOIN (
SELECT time, cluster, __value__ AS up
FROM B
WHERE cluster != 'fake'
ORDER BY time
LIMIT 5
) b ON a.time = b.time;
This approach ensures that a schema exists even when one query returns no data.
Create the following Prometheus query:
sum(
rate(go_cpu_classes_gc_total_cpu_seconds_total{namespace=~".*(namespace).*5."}[$__rate_interval])
) by (namespace)
The panel displays the CPU usage by Go garbage collection (GC) over time, broken down by namespace.
Add the SQL expression SELECT * from A. After you add a SQL expression that selects from RefID A, Grafana converts it to a table response:
The Grafana LLM plugin seamlessly integrates AI-powered assistance into your SQL expressions workflow.
{{< admonition type="note" >}} The Grafana LLM plugin is currently in public preview, meaning Grafana offers limited support, and breaking changes might occur prior to the feature being made generally available. {{< /admonition >}}
To use this integration, first install and configure the LLM plugin. After installation, open your dashboard and select Edit to open the panel editor. Navigate to the Queries tab and scroll to the bottom where you'll find two new buttons positioned to the right of the Run query button in your SQL Expressions query.
{{< figure src="/media/docs/sql-expressions/sqlexpressions-LLM-integration-v12.2.png" caption="LLM integration" >}}
Click Explain query to open a drawer that displays a detailed explanation of your query, including its interpreted business meaning and performance statistics. Once the explanation is generated, the button changes to View explanation.
Click Improve query to open a suggestions drawer that contains performance and reliability enhancements, column naming best practices, and guidance on panel optimization. Click Apply to implement a suggestion. After you’ve interacted with the interface, you'll see a Suggestions button for quick access. Newer suggestions appear at the top, with older ones listed below, creating a history of improvements. If your SQL query has a parsing error, such as a syntax issue, the LLM will attempt to provide a corrected version. The LLM automatically identifies errors and helps you rewrite the query correctly.