Enterprise Grafana Cloud
Last reviewed: August 26, 2026

SAP HANA query editor

The SAP HANA query editor is where you turn your database into dashboards. Write SQL directly against your SAP HANA instance, then shape the results into time series, tables, or logs. Open it from any dashboard panel by clicking the panel menu and selecting Edit, or from the Explore page for quick, exploratory queries.

This document focuses on what’s specific to querying SAP HANA. For guidance that applies to every data source, refer to Query and transform data.

Key concepts

If you’re new to SAP HANA, the following are key terms used in this documentation:

TermDescription
SchemaA container for database objects like tables and views.
Time seriesData points indexed in time order, typically used for graphs.
Table dataStructured data returned in rows and columns.
MacroA placeholder that Grafana expands into an SQL expression based on the dashboard context.

Query editor features

The SAP HANA query editor provides the following features:

  • SQL query editor: Enter any HANA SQL queries directly.
  • Syntax highlighting: SQL syntax is highlighted for readability.
  • Auto-completion: Grafana macros and template variables are auto-completed as you type.
  • Format options: Format query results as time series, table, or logs.
  • Keyboard shortcut: Press Ctrl+S (or Cmd+S on Mac) to re-run the query while editing.

Create a query

To create a query:

  1. Select the SAP HANA data source.
  2. Enter your SQL query in the query editor.
  3. Select the Format option:
    • Time series: For visualizing data in graph panels.
    • Table: For displaying data in table panels.
    • Logs: For viewing data in the Logs panel in Explore.
  4. Click Run query to execute.

Time series queries

For time series visualizations, your query must return at least one time column and one numeric value column. The time column should be named time or use a timestamp data type.

Example:

SQL
SELECT "ts" AS "time", "temperature" AS "value"
FROM "weather"
WHERE $__timeFilter(ts)
ORDER BY "ts" ASC

To return multiple series from a single query, include a text column whose values become the series names. The following query returns one series per region:

SQL
SELECT
  $__timeGroup("timestamp", $__interval),
  "region" AS "metric",
  AVG("sales") AS "sales"
FROM "salesdata"
WHERE $__timeFilter("timestamp")
GROUP BY $__timeGroup("timestamp", $__interval), "region"
ORDER BY $__timeGroup("timestamp", $__interval) ASC

Table queries

For table visualizations, your query can return any columns. The results display in a tabular format.

Example:

SQL
SELECT username, city, age
FROM users
WHERE city = 'London'

Macros

Macros are placeholders that Grafana expands into SQL expressions based on the dashboard time range and other context. The query editor auto-completes supported macros.

Available macros

MacroDescription
$__timeFilter(<time_column>)Applies the Grafana time range to the specified column. Applicable to date/timestamp/long time columns.
$__timeFilter(<time_column>,<format>)Same as above, but specify the format of the time column stored in the database.
$__timeFilter(<time_column>,"epoch",<format>)Use when your time column is in epoch format. Format can be s, ms, or ns.
$__timeFilterEpoch(<time_column>)Applies the Grafana time range to an epoch time column by comparing the raw epoch value. Defaults to seconds. Pass an optional format of s, ms, or ns as the second argument. $__unixEpochFilter is an alias, provided for consistency with the MySQL and PostgreSQL data sources.
$__fromTimeFilter(<time_column>)Returns a time condition based on the Grafana From time.
$__fromTimeFilter(<time_column>,<comparison_predicate>)Same as above, but specify the comparison predicate.
$__fromTimeFilter(<time_column>,<format>)Same as above, but specify the format of the time column.
$__fromTimeFilter(<time_column>,<format>,<comparison_predicate>)Specify both format and comparison predicate.
$__toTimeFilter(<time_column>)Returns a time condition based on the Grafana To time.
$__toTimeFilter(<time_column>,<comparison_predicate>)Same as above, but specify the comparison predicate.
$__toTimeFilter(<time_column>,<format>)Same as above, but specify the format of the time column.
$__toTimeFilter(<time_column>,<format>,<comparison_predicate>)Specify both format and comparison predicate.
$__timeGroup(<time_column>,<interval>)Groups time into interval buckets. Expands to SERIES_ROUND().
$__timeGroup(<time_column>,<interval>,<round_mode>)Same as above, with an optional rounding mode (for example, ROUND_HALF_UP).
$__fromTimeStamp()Expands to the From timestamp. Example: timestamp'2023-01-11T00:02:03Z'
$__toTimeStamp()Expands to the To timestamp. Example: timestamp'2023-01-12T00:02:03Z'
$__intervalThe Grafana calculated interval based on the time range and panel width. Example: 1h, 5m.
$__interval_sThe interval in seconds. Example: 3600 for a 1-hour interval.
$__interval_msThe interval in milliseconds. Example: 3600000 for a 1-hour interval.

$__timeFilter macro

The $__timeFilter(<time_column>) macro applies the dashboard time range to a column.

Example:

SQL
-- Query with macro
SELECT ts, temperature FROM weather WHERE $__timeFilter(ts)

-- Expands to
SELECT ts, temperature FROM weather WHERE "ts" > '2021-02-24T12:52:48Z' AND "ts" < '2021-03-24T12:52:48Z'

$__timeFilter with custom format

If your time column is stored in a custom format, specify the format as the second argument.

Example:

SQL
-- Time column in YYYYMMDDHH24MISS format (e.g., 20210421162012)
SELECT TO_TIMESTAMP("TS",'YYYYMMDDHH24MISS') AS METRIC_TIME, "VALUE"
FROM "SCH"."TBL"
WHERE $__timeFilter("TS","YYYYMMDDHH24MISS")

-- Time column in YYYY-MON-DD format (e.g., 2021-JAN-15)
SELECT TO_TIMESTAMP("TS",'YYYY-MON-DD') AS METRIC_TIME, "VALUE"
FROM "SCH"."TBL"
WHERE $__timeFilter("TS","YYYY-MON-DD")

$__timeFilter with epoch timestamps

For epoch timestamps, use the "epoch" format with a precision specifier.

Example:

SQL
-- Epoch seconds (e.g., 1257894000)
SELECT ADD_SECONDS('1970-01-01', "TIMESTAMP") AS "METRIC_TIME", "VALUE"
FROM "SCH"."TBL"
WHERE $__timeFilter("TIMESTAMP","epoch","s")

-- Epoch milliseconds (e.g., 1257894000000)
SELECT ADD_SECONDS('1970-01-01', "TIMESTAMP"/1000) AS "METRIC_TIME", "VALUE"
FROM "SCH"."TBL"
WHERE $__timeFilter("TIMESTAMP","epoch","ms")

-- Epoch nanoseconds (e.g., 1257894000000000000)
SELECT ADD_SECONDS('1970-01-01', "TIMESTAMP"/1000000000) AS "METRIC_TIME", "VALUE"
FROM "SCH"."TBL"
WHERE $__timeFilter("TIMESTAMP","epoch","ns")

You can also use shorthand notation:

SQL
-- These are equivalent
$__timeFilter("TIMESTAMP","epoch","ms")
$__timeFilter("TIMESTAMP","epoch_ms")

$__fromTimeFilter and $__toTimeFilter macros

These macros return conditions based on the Grafana From or To time.

Parameters:

  • <time_column>: The time field name.
  • <format>: Optional. Format of the time column. Can be epoch_s, epoch_ms, epoch_ns, or a custom format like YYYY-MM-DD.
  • <comparison_predicate>: Optional. Comparison operator. Default is > for $__fromTimeFilter and < for $__toTimeFilter. Can be =, !=, <>, <, <=, >, or >=.

Examples:

SQL
$__fromTimeFilter("TS")                         -- "TS" > '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS",">=")                    -- "TS" >= '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","epoch_ms")              -- ADD_SECONDS('1970-01-01', ("TS" / 1000)) > '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","YYYYMMDDHH24MISS",">=") -- TO_TIMESTAMP("TS",'YYYYMMDDHH24MISS') >= '2014-11-12T11:45:26Z'
$__toTimeFilter("TS")                           -- "TS" < '2015-11-12T11:45:26Z'

$__fromTimeStamp and $__toTimeStamp macros

These macros return SAP HANA timestamp literals for the dashboard’s From and To times.

Example:

SQL
-- Use timestamps directly in expressions
SELECT * FROM "events"
WHERE "event_time" BETWEEN $__fromTimeStamp() AND $__toTimeStamp()

-- Expands to
SELECT * FROM "events"
WHERE "event_time" BETWEEN timestamp'2014-11-12T11:45:26Z' AND timestamp'2015-11-12T11:45:26Z'

$__timeGroup macro

The $__timeGroup(<time_column>,<interval>) macro groups time into interval buckets using the SAP HANA SERIES_ROUND function.

You can also specify an optional third argument for the rounding mode:

$__timeGroup(<time_column>,<interval>,<round_mode>)

The round mode is passed directly to the SAP HANA SERIES_ROUND function. Common values include ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_UP, ROUND_DOWN, ROUND_CEILING, and ROUND_FLOOR.

Example with rounding mode:

SQL
-- Round timestamps down to the nearest hour
SELECT $__timeGroup(timestamp, 1h, ROUND_DOWN), avg("value") as "value"
FROM "salesdata"
WHERE $__timeFilter("timestamp")
GROUP BY $__timeGroup(timestamp, 1h, ROUND_DOWN)

Valid intervals:

IntervalDuration
msMILLISECOND (converted to fractional seconds)
sSECOND
mMINUTE
hHOUR
dDAY
MMONTH
yYEAR

Example:

SQL
-- Query with macro
SELECT $__timeGroup(timestamp,1h), "user", sum("value") as "value"
FROM "salesdata"
WHERE $__timeFilter("timestamp")
GROUP BY $__timeGroup(timestamp,1h), "user"
ORDER BY $__timeGroup(timestamp,1h) ASC

-- Expands to
SELECT SERIES_ROUND("timestamp", 'INTERVAL 1 HOUR'), "user", sum("value") as "value"
FROM "salesdata"
WHERE "timestamp" > '2020-01-01T00:00:00Z' AND "timestamp" < '2020-01-01T23:00:00Z'
GROUP BY SERIES_ROUND("timestamp", 'INTERVAL 1 HOUR'), "user"
ORDER BY SERIES_ROUND("timestamp", 'INTERVAL 1 HOUR') ASC

Note

The $__timeGroup macro expands to a SERIES_ROUND expression without an alias, and SAP HANA doesn’t accept a column alias in GROUP BY. Repeat the full macro in your SELECT, GROUP BY, and ORDER BY clauses rather than referencing an alias. Otherwise, SAP HANA may not recognize the query.

Use dynamic intervals

Instead of using a fixed interval, use $__interval to let Grafana calculate the interval based on the dashboard time range:

SQL
SELECT $__timeGroup(timestamp, $__interval), sum("value") as "value"
FROM "salesdata"
WHERE $__timeFilter("timestamp")
GROUP BY $__timeGroup(timestamp, $__interval)
ORDER BY $__timeGroup(timestamp, $__interval) ASC

For more information about global variables, refer to Built-in variables.

Use interval values in calculations

Use $__interval_s or $__interval_ms when you need the interval as a number for calculations:

SQL
-- Calculate rate per second using the interval
SELECT $__timeGroup(timestamp, $__interval), 
       sum("bytes") / $__interval_s as "bytes_per_second"
FROM "network_traffic"
WHERE $__timeFilter("timestamp")
GROUP BY $__timeGroup(timestamp, $__interval)

Macro examples

The following examples show macro expansions when the dashboard has 2014-11-12T11:45:26.371Z as the From time and 2015-11-12T11:45:26.371Z as the To time.

MacroExpands to
$__timeFilter("TS")"TS" > '2014-11-12T11:45:26Z' AND "TS" < '2015-11-12T11:45:26Z'
$__timeFilter("TS","YYYYMMDDHH24MISS")TO_TIMESTAMP("TS",'YYYYMMDDHH24MISS') > '2014-11-12T11:45:26Z' AND TO_TIMESTAMP("TS",'YYYYMMDDHH24MISS') < '2015-11-12T11:45:26Z'
$__timeFilter("TS","epoch_ms")"TS" > '1415792726000' AND "TS" < '1447328726000'
$__timeFilter("TS","epoch_ns")"TS" > '1415792726000000000' AND "TS" < '1447328726000000000'
$__fromTimeFilter("TS")"TS" > '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","epoch")ADD_SECONDS( '1970-01-01', "TS" ) > '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","epoch_s")ADD_SECONDS( '1970-01-01', "TS" ) > '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","epoch_ms")ADD_SECONDS( '1970-01-01', ("TS" / 1000)) > '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","epoch_ns")ADD_SECONDS( '1970-01-01', ("TS" / 1000000000)) > '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","YYYYMMDDHH24MISS")TO_TIMESTAMP("TS",'YYYYMMDDHH24MISS') > '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS",">=")"TS" >= '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","epoch_ms",">=")ADD_SECONDS( '1970-01-01', ("TS" / 1000)) >= '2014-11-12T11:45:26Z'
$__fromTimeFilter("TS","YYYYMMDDHH24MISS",">=")TO_TIMESTAMP("TS",'YYYYMMDDHH24MISS') >= '2014-11-12T11:45:26Z'
$__toTimeFilter("TS")"TS" < '2015-11-12T11:45:26Z'
$__timeGroup("TS","1h")SERIES_ROUND("TS", 'INTERVAL 1 HOUR')
$__timeGroup("TS","$__interval")SERIES_ROUND("TS", 'INTERVAL 6 HOUR')

Grafana global time variables

In addition to the plugin’s own macros, you can use the built-in Grafana global variables ${__from} and ${__to} in your queries. These resolve to the dashboard’s time range. The query editor auto-completes these variables.

Because the data source quotes variable values with single quotes by default, ${__from} and ${__to} insert a quoted string such as '1594671549254'. To insert an unquoted value, apply an explicit format such as ${__from:date:seconds} or ${__from:raw}. These global variables are resolved when a dashboard panel renders and aren’t expanded during alert evaluation. For alerting, use the $__fromTimeStamp() and $__toTimeStamp() macros instead.

VariableExample valueDescription
${__from}1594671549254Unix millisecond epoch of the From time.
${__from:date}2020-07-13T20:19:09.254ZISO 8601/RFC 3339 (default when no format is given).
${__from:date:iso}2020-07-13T20:19:09.254ZISO 8601/RFC 3339.
${__from:date:seconds}1594671549Unix seconds epoch.
${__from:date:YYYY-MM}2020-07Any custom date format that doesn’t include the : character.
${__to}1594671549254Unix millisecond epoch of the To time.
${__to:date}2020-07-13T20:19:09.254ZISO 8601/RFC 3339 (default when no format is given).

For the complete list, refer to Global variables.

Visualize data as logs

To visualize data in the Logs viewer in Explore, select the Logs format for your query.

Requirements

Your log query must include:

  • At least one time column (timestamp)
  • At least one string column for the log content

Optionally, you can include a level column to set the log level for each row. For supported log levels and their keywords, refer to Logs in Explore.

Any additional columns in your query are treated as additional fields or detected fields in the logs.

Example log query

SQL
SELECT 'hello foo' AS "content", timestamp'2021-12-31 23:59:59' AS "start_time", 'warn'  AS "level" FROM DUMMY UNION
SELECT 'hello bar' AS "content", timestamp'2021-12-30 14:12:59' AS "start_time", 'error' AS "level" FROM DUMMY UNION
SELECT 'hello baz' AS "content", timestamp'2021-12-30 23:59:59' AS "start_time", 'warn' AS "level" FROM DUMMY UNION
SELECT 'hello qux' AS "content", timestamp'2021-12-29 23:59:59' AS "start_time", 'info' AS "level" FROM DUMMY UNION
SELECT 'hello quux' AS "content", timestamp'2021-12-28 23:59:59' AS "start_time", 'unknown' AS "level" FROM DUMMY UNION
SELECT 'hello quuz' AS "content", timestamp'2021-12-27 23:59:59' AS "start_time", 'info' AS "level" FROM DUMMY;

Additional resources