菜单
Grafana Cloud 企业版 开源版

Microsoft SQL Server 查询编辑器

编辑使用 MS SQL 数据源的面板时,可以使用 Microsoft SQL Server 数据源的查询编辑器创建查询。

本主题介绍针对 MS SQL 数据源的特定查询。有关在 Grafana 中查询数据源的通用文档,请参阅查询和转换数据

选择查询编辑模式

您可以在两种模式之间切换查询编辑器

  • 代码模式,它提供了一个功能丰富的编辑器用于编写查询
  • 构建器模式,它提供了一个可视化查询设计器

要在编辑器模式之间切换,请选择编辑器上方的相应 构建器代码 选项卡。

要运行查询,请选择编辑器右上角的 运行查询

查询编辑器还提供了

配置通用选项

无论何种模式,您都可以在查询编辑器中配置 MS SQL 特定的响应格式。

选择响应格式

Grafana 可以将 MS SQL 的响应格式化为表格或时间序列。

要选择响应格式,请从 格式 下拉菜单中选择 表格时间序列 格式。

要使用时间序列格式,您必须将其中一个 MS SQL 列命名为 time。您可以在告警条件中使用时间序列查询,但不能使用表格查询。

有关使用这些格式的详细信息,请参阅使用表格查询使用时间序列查询

代码模式

代码模式 下,您可以使用带有自动补全功能和语法高亮的文本编辑器编写复杂查询。

有关 Microsoft SQL Server 使用的查询语言 Transact-SQL (T-SQL) 的更多信息,请参阅Transact-SQL 教程

使用工具栏功能

代码模式在编辑器右下角的工具栏中提供了几个功能。

要重新格式化查询,请单击大括号按钮 ({})。

要展开代码编辑器,请单击向下指的箭头按钮。

要运行查询,请单击 运行查询 按钮或使用键盘快捷键Ctrl/Cmd + Enter/Return.

使用自动补全

代码模式的自动补全功能在您输入时自动工作。要手动触发自动补全,请使用键盘快捷键Ctrl/Cmd + 空格.

代码模式支持自动补全表、列、SQL 关键字、标准 SQL 函数、Grafana 模板变量和 Grafana 宏。

注意:在指定表之前,您无法自动补全列。

构建器模式

构建器模式 下,您可以使用可视化界面构建查询。

数据集和表选择

数据集 下拉菜单中,选择要查询的 MSSQL 数据库。Grafana 会用用户可以访问的所有数据库填充该下拉菜单。选择数据库后,Grafana 会用所有可用表填充该下拉菜单。

注意:如果通过数据源配置页面(或通过配置提供文件)配置了默认数据库,则用户只能使用该单个预配置的数据库进行查询。

我们不包含查询编辑器下拉菜单中的 tempdbmodelmsdbmaster 数据库。

选择列和聚合函数 (SELECT)

下拉菜单中选择一个列将其包含在数据中。您可以在 聚合 下拉菜单中为该列选择一个可选的聚合函数。

要添加更多值列,请单击列行右侧的加号 (+) 按钮。

您可以在 select 子句中启用宏支持以创建时间序列查询。

使用 数据操作 下拉菜单选择一个宏,例如 $__timeGroup$__timeGroupAlias。从 下拉菜单中选择一个时间列,并从 间隔 下拉菜单中选择一个时间间隔,以创建时间序列查询。

SQL query builder time-series query
SQL 查询构建器时间序列查询

您还可以向 数据操作 添加自定义值。例如,一个不在下拉列表中的函数。这允许您添加任意数量的参数。

过滤数据 (WHERE)

要添加过滤器,请切换编辑器顶部的 过滤器 开关。这将显示一个 按列值过滤 部分,其中有两个下拉选择器。

使用第一个下拉菜单选择所有过滤器都需要匹配 (AND),还是只需一个过滤器匹配 (OR)。使用第二个下拉菜单选择一个过滤器。

要在更多列上过滤,请单击条件下拉菜单右侧的加号 (+) 按钮。

要移除过滤器,请单击该过滤器下拉菜单旁边的 x 按钮。

选择日期类型列后,您可以从运算符列表中选择宏,并选择 timeFilter,它会将 $__timeFilter 宏添加到具有所选日期列的查询中。

分组结果

要按列对结果进行分组,请切换编辑器顶部的 分组 开关。这将显示一个 按列分组 下拉菜单,您可以在其中选择要按哪个列对结果进行分组。

要移除 group-by 子句,请单击 x 按钮。

预览查询

要预览构建器模式生成的 SQL 查询,请切换编辑器顶部的 预览 开关。这将显示一个包含查询的预览窗格,以及右上角的一个复制图标,用于将查询复制到剪贴板。

使用宏

为了简化语法并允许动态组件(如日期范围过滤器),您可以将宏添加到查询中。

宏示例替换为
$__time(dateColumn)将列重命名为 time 的表达式。例如,dateColumn as time
$__timeEpoch(dateColumn)将 DATETIME 列类型转换为 Unix 时间戳并将其重命名为 time 的表达式。
例如,DATEDIFF(second, ‘1970-01-01’, dateColumn) AS time
$__timeFilter(dateColumn)使用指定列名称的时间范围过滤器。
例如,dateColumn BETWEEN ‘2017-04-21T05:01:17Z’ AND ‘2017-04-21T05:06:17Z’
$__timeFrom()当前活动时间选择的开始。例如,‘2017-04-21T05:01:17Z’
$__timeTo()当前活动时间选择的结束。例如,‘2017-04-21T05:06:17Z’
$__timeGroup(dateColumn,'5m'[, fillvalue])在 GROUP BY 子句中可用的表达式。提供 NULL浮点值fillValue 将自动使用该值填充时间范围内的空序列。
例如,CAST(ROUND(DATEDIFF(second, ‘1970-01-01’, time_column)/300.0, 0) as bigint)*300
$__timeGroup(dateColumn,'5m', 0)与上面相同,但带有填充参数,因此 Grafana 将添加该序列中缺失的点,并使用 0 作为值。
$__timeGroup(dateColumn,'5m', NULL)与上面相同,但对于缺失的点将使用 NULL 作为值。
$__timeGroup(dateColumn,'5m', previous)与上面相同,但如果尚未看到任何值,则将使用该序列中的上一个值作为填充值,否则将使用 NULL。
$__timeGroupAlias(dateColumn,'5m')$__timeGroup 相同,但添加了列别名。
$__unixEpochFilter(dateColumn)使用指定列名称的时间范围过滤器,时间表示为 Unix 时间戳。例如,dateColumn > 1494410783 AND dateColumn < 1494497183
$__unixEpochFrom()当前活动时间选择的开始,表示为 Unix 时间戳。例如,1494410783
$__unixEpochTo()当前活动时间选择的结束,表示为 Unix 时间戳。例如,1494497183
$__unixEpochNanoFilter(dateColumn)使用指定列名称的时间范围过滤器,时间表示为纳秒时间戳。例如,dateColumn > 1494410783152415214 AND dateColumn < 1494497183142514872
$__unixEpochNanoFrom()当前活动时间选择的开始,表示为纳秒时间戳。例如,1494410783152415214
$__unixEpochNanoTo()当前活动时间选择的结束,表示为纳秒时间戳。例如,1494497183142514872
$__unixEpochGroup(dateColumn,'5m', [fillmode])$__timeGroup 相同,但用于存储为 Unix 时间戳的时间。
$__unixEpochGroupAlias(dateColumn,'5m', [fillmode])与上面相同,但还添加了列别名。

查看插值查询

查询编辑器还包含一个名为 生成的 SQL 的链接,该链接在面板编辑模式下运行查询后出现。要显示数据源执行的原始插值 SQL 字符串,请单击此链接。

使用表格查询

如果 表格面板格式 查询选项设置为 表格,您可以输入任何类型的 SQL 查询。然后表格面板将显示返回的所有列和行的查询结果。

示例数据库表

sql
CREATE TABLE [event] (
  time_sec bigint,
  description nvarchar(100),
  tags nvarchar(100),
)
sql
CREATE TABLE [mssql_types] (
  c_bit bit, c_tinyint tinyint, c_smallint smallint, c_int int, c_bigint bigint, c_money money, c_smallmoney smallmoney, c_numeric numeric(10,5),
  c_real real, c_decimal decimal(10,2), c_float float,
  c_char char(10), c_varchar varchar(10), c_text text,
  c_nchar nchar(12), c_nvarchar nvarchar(12), c_ntext ntext,
  c_datetime datetime,  c_datetime2 datetime2, c_smalldatetime smalldatetime, c_date date, c_time time, c_datetimeoffset datetimeoffset
)

INSERT INTO [mssql_types]
SELECT
  1, 5, 20020, 980300, 1420070400, '$20000.15', '£2.15', 12345.12,
  1.11, 2.22, 3.33,
  'char10', 'varchar10', 'text',
  N'☺nchar12☺', N'☺nvarchar12☺', N'☺text☺',
  GETDATE(), CAST(GETDATE() AS DATETIME2), CAST(GETDATE() AS SMALLDATETIME), CAST(GETDATE() AS DATE), CAST(GETDATE() AS TIME), SWITCHOFFSET(CAST(GETDATE() AS DATETIMEOFFSET), '-07:00')

带有示例查询的查询编辑器

查询

sql
SELECT * FROM [mssql_types]

要控制表格面板列的名称,请使用标准的 AS SQL 列选择语法。

例如

sql
SELECT
  c_bit as [column1], c_tinyint as [column2]
FROM
  [mssql_types]

结果表格面板

使用时间序列查询

注意

将时间戳存储为 UTC,以避免在使用非 UTC 时区时 Grafana 中出现时间偏移问题。

如果将查询编辑器中的 格式 设置设置为 时间序列,则查询必须有一个名为 time 的列,该列返回 SQL datetime 类型或表示 Unix epoch(秒)的任何数字数据类型。时间序列查询的结果集也必须按时间排序,以便面板正确可视化结果。

时间序列查询结果以宽数据帧格式返回。除 time 列或字符串类型的列外,任何列都将转换为数据帧查询结果中的值字段。任何字符串列都将转换为数据帧查询结果中的字段标签。

创建指标查询

为了向后兼容,对于返回三列且包含名为 metric 的字符串列的查询,有一个例外。metric 列不会转换为字段标签,而是成为字段名,然后序列名格式化为 metric 列的值。请参阅下面的带有 metric 列的示例。

要选择性地自定义默认序列名称格式,请参阅标准选项定义

带有 metric 列的示例

sql
SELECT
  $__timeGroupAlias(time_date_time, '5m'),
  min("value_double"),
  'min' as metric
FROM test_data
WHERE $__timeFilter(time_date_time)
GROUP BY time
ORDER BY 1

数据帧结果

text
+---------------------+-----------------+
| Name: time          | Name: min       |
| Labels:             | Labels:         |
| Type: []time.Time   | Type: []float64 |
+---------------------+-----------------+
| 2020-01-02 03:05:00 | 3               |
| 2020-01-02 03:10:00 | 6               |
+---------------------+-----------------+

时间序列查询示例

在 $__timeGroupAlias 宏中使用 fill 参数将 null 值转换为零

sql
SELECT
  $__timeGroupAlias(createdAt, '5m', 0),
  sum(value) as value,
  hostname
FROM test_data
WHERE
  $__timeFilter(createdAt)
GROUP BY
  time,
  hostname
ORDER BY 1

根据以下示例中的数据帧结果并使用图形面板,您将获得两个名为 value 10.0.1.1value 10.0.1.2 的序列。要以 10.0.1.110.0.1.2 的名称渲染序列,请使用标准选项定义中的显示名称值 ${__field.labels.hostname}

数据帧结果

text
+---------------------+---------------------------+---------------------------+
| Name: time          | Name: value               | Name: value               |
| Labels:             | Labels: hostname=10.0.1.1 | Labels: hostname=10.0.1.2 |
| Type: []time.Time   | Type: []float64           | Type: []float64           |
+---------------------+---------------------------+---------------------------+
| 2020-01-02 03:05:00 | 3                         | 4                         |
| 2020-01-02 03:10:00 | 6                         | 7                         |
+---------------------+---------------------------+---------------------------+

使用多列

sql
SELECT
  $__timeGroupAlias(time_date_time, '5m'),
  min(value_double) as min_value,
  max(value_double) as max_value
FROM test_data
WHERE $__timeFilter(time_date_time)
GROUP BY time
ORDER BY 1

数据帧结果

text
+---------------------+-----------------+-----------------+
| Name: time          | Name: min_value | Name: max_value |
| Labels:             | Labels:         | Labels:         |
| Type: []time.Time   | Type: []float64 | Type: []float64 |
+---------------------+-----------------+-----------------+
| 2020-01-02 03:04:00 | 3               | 4               |
| 2020-01-02 03:05:00 | 6               | 7               |
+---------------------+-----------------+-----------------+

应用标注

标注在图表上方叠加丰富的事件信息。您可以在仪表盘菜单的标注视图中添加标注查询。

名称描述
time日期/时间字段的名称。可以是具有本机 SQL 日期/时间数据类型或 epoch 值的列。
timeend结束日期/时间字段的可选名称。可以是具有本机 SQL 日期/时间数据类型或 epoch 值的列。
text事件描述字段。
tags用作事件标签的可选字段名称,作为逗号分隔的字符串。

示例数据库表

sql
CREATE TABLE [events] (
  time_sec bigint,
  description nvarchar(100),
  tags nvarchar(100),
)

我们还使用了时间序列查询中定义的数据库表。

使用带有 epoch 值的时间列的示例查询

sql
SELECT
  time_sec as time,
  description as [text],
  tags
FROM
  [events]
WHERE
  $__unixEpochFilter(time_sec)
ORDER BY 1

使用带有 epoch 值的时间和 timeend 列的示例区域查询

sql
SELECT
  time_sec as time,
  time_end_sec as timeend,
  description as [text],
  tags
FROM
  [events]
WHERE
  $__unixEpochFilter(time_sec)
ORDER BY 1

使用本机 SQL 日期/时间数据类型的时间列的示例查询

sql
SELECT
  time,
  measurement as text,
  convert(varchar, valueOne) + ',' + convert(varchar, valueTwo) as tags
FROM
  metric_values
WHERE
  $__timeFilter(time_column)
ORDER BY 1

使用存储过程

存储过程已验证可用。但请注意,我们没有为此提供特殊支持,因此可能存在一些边缘情况导致其无法按预期工作。只要您使用与上面各节中描述的相同的列命名和返回数据格式,存储过程应支持表格、时间序列和标注查询。

请注意,任何宏函数都不会在存储过程内部工作。

示例

对于以下示例,数据库表在时间序列查询中定义。假设我们想在图表面板中可视化四个序列,例如列valueOnevalueTwomeasurement的所有组合。右侧的图表面板可视化了我们想要实现的目标。要解决这个问题,我们需要使用两个查询

第一个查询

sql
SELECT
  $__timeGroup(time, '5m') as time,
  measurement + ' - value one' as metric,
  avg(valueOne) as valueOne
FROM
  metric_values
WHERE
  $__timeFilter(time)
GROUP BY
  $__timeGroup(time, '5m'),
  measurement
ORDER BY 1

第二个查询

sql
SELECT
  $__timeGroup(time, '5m') as time,
  measurement + ' - value two' as metric,
  avg(valueTwo) as valueTwo
FROM
  metric_values
GROUP BY
  $__timeGroup(time, '5m'),
  measurement
ORDER BY 1

使用 epoch 时间格式的存储过程

我们可以定义一个存储过程,用于返回在上述图表面板中呈现 4 个序列所需的所有数据。在此存储过程中,它接受两个 int 数据类型的参数 @from@to,这两个参数应是 epoch 格式的时间范围(从-到),用于过滤存储过程返回的数据。

我们正在模仿 select 和 group by 表达式中的 $__timeGroup(time, '5m'),这就是为什么需要很多冗长的表达式——如果需要,可以将这些提取到 MS SQL 函数中。

sql
CREATE PROCEDURE sp_test_epoch(
  @from int,
  @to 	int
)	AS
BEGIN
  SELECT
    cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int) as time,
    measurement + ' - value one' as metric,
    avg(valueOne) as value
  FROM
    metric_values
  WHERE
    time >= DATEADD(s, @from, '1970-01-01') AND time <= DATEADD(s, @to, '1970-01-01')
  GROUP BY
    cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int),
    measurement
  UNION ALL
  SELECT
    cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int) as time,
    measurement + ' - value two' as metric,
    avg(valueTwo) as value
  FROM
    metric_values
  WHERE
    time >= DATEADD(s, @from, '1970-01-01') AND time <= DATEADD(s, @to, '1970-01-01')
  GROUP BY
    cast(cast(DATEDIFF(second, {d '1970-01-01'}, DATEADD(second, DATEDIFF(second,GETDATE(),GETUTCDATE()), time))/600 as int)*600 as int),
    measurement
  ORDER BY 1
END

然后我们可以将以下查询用于我们的图表面板。

sql
DECLARE
  @from int = $__unixEpochFrom(),
  @to int = $__unixEpochTo()

EXEC dbo.sp_test_epoch @from, @to

使用 datetime 时间格式的存储过程

我们可以定义一个存储过程,用于返回在上述图表面板中呈现 4 个序列所需的所有数据。在此存储过程中,它接受两个 datetime 数据类型的参数 @from@to,这两个参数应是时间范围(从-到),用于过滤存储过程返回的数据。

我们正在模仿 select 和 group by 表达式中的 $__timeGroup(time, '5m'),这就是为什么需要很多冗长的表达式——如果需要,可以将这些提取到 MS SQL 函数中。

sql
CREATE PROCEDURE sp_test_datetime(
  @from datetime,
  @to 	datetime
)	AS
BEGIN
  SELECT
    cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int) as time,
    measurement + ' - value one' as metric,
    avg(valueOne) as value
  FROM
    metric_values
  WHERE
    time >= @from AND time <= @to
  GROUP BY
    cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int),
    measurement
  UNION ALL
  SELECT
    cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int) as time,
    measurement + ' - value two' as metric,
    avg(valueTwo) as value
  FROM
    metric_values
  WHERE
    time >= @from AND time <= @to
  GROUP BY
    cast(cast(DATEDIFF(second, {d '1970-01-01'}, time)/600 as int)*600 as int),
    measurement
  ORDER BY 1
END

然后我们可以将以下查询用于我们的图表面板。

sql
DECLARE
  @from datetime = $__timeFrom(),
  @to datetime = $__timeTo()

EXEC dbo.sp_test_datetime @from, @to