使用 Grafana 的(TimescaleDB)SQL 插件进行多连接的 Groupby 问题

Posted

技术标签:

【中文标题】使用 Grafana 的(TimescaleDB)SQL 插件进行多连接的 Groupby 问题【英文标题】:Groupby issue on multiple join using Grafana's (TimescaleDB) SQL plugin 【发布时间】:2021-04-29 12:06:57 【问题描述】:

我正在使用 Grafana 的 SQL 插件来查询 TimescaleDB 数据库。

数据库将天气信息存储为

| timestamp | location_id | data_type_id | value |

其中location_iddata_type_id 是表locations 的外键描述位置,weather_data_types 定义测量类型(温度、相对湿度...)。

我想查询某个时间范围内的数据,按位置和类型分组。

我设法按其中一个分组,但不能同时分组。

这适用于按位置分组:

SELECT
  $__timeGroupAlias("timestamp", $__interval),
  avg(value),
  locations.name
FROM weather_data
JOIN locations ON weather_data.location_id = locations.id
GROUP BY 1, locations.name
ORDER BY 1

这适用于按类型分组:

SELECT
  $__timeGroupAlias("timestamp", $__interval),
  avg(value),
  weather_data_types.name
FROM weather_data
JOIN weather_data_types ON weather_data.type_id = weather_data_types.id
GROUP BY 1, weather_data_types.name
ORDER BY 1

这不起作用:

SELECT
  $__timeGroupAlias("timestamp", $__interval),
  avg(value),
  locations.name,
  weather_data_types.name
FROM weather_data
JOIN locations ON weather_data.location_id = locations.id
JOIN weather_data_types ON weather_data.type_id = weather_data_types.id
GROUP BY 1, locations.name, weather_data_types.name
ORDER BY 1

更具体地说,我收到以下错误

Value column must have numeric datatype, column: name type: string value: relative_humidity

似乎第三个 groupby (静默)没有发生,并且返回了 weather_data_types.name,Grafana 抱怨说它无法绘制字符串。

将其更改为返回(整数)id 会删除错误消息

SELECT
  $__timeGroupAlias("timestamp", $__interval),
  avg(value),
  locations.name,
  weather_data_types.id
FROM weather_data
JOIN locations ON weather_data.location_id = locations.id
JOIN weather_data_types ON weather_data.type_id = weather_data_types.id
GROUP BY 1, locations.name, weather_data_types.id
ORDER BY 1

但绘制了两个系列:avgid,这表明未应用 groupby 类型。

我的查询有什么问题吗?是 Grafana 插件的问题吗?


我认为这并不重要,但这里是模型,用 SQLAlchemy 定义,希望不言自明。

class Location(Base):
    __tablename__ = "locations"

    id = sqla.Column(sqla.Integer, primary_key=True)
    name = sqla.Column(sqla.String(80), unique=True, nullable=False)
    country = sqla.Column(sqla.String(80), nullable=False)
    latitude = sqla.Column(sqla.Float(), nullable=False)
    longitude = sqla.Column(sqla.Float(), nullable=False)


class WeatherDataTypes(Base):
    __tablename__ = "weather_data_types"

    id = sqla.Column(sqla.Integer, primary_key=True)
    name = sqla.Column(sqla.String(80), unique=True, nullable=False)
    description = sqla.Column(sqla.String(500), nullable=False)
    unit = sqla.Column(sqla.String(20), nullable=False)
    min_value = sqla.Column(sqla.Float)
    max_value = sqla.Column(sqla.Float)


class WeatherData(Base):
    __tablename__ = "weather_data"

    timestamp = sqla.Column(sqla.DateTime(timezone=True), primary_key=True)
    location_id = sqla.Column(
        sqla.Integer,
        sqla.ForeignKey('locations.id'),
        nullable=False,
        primary_key=True
    )
    location = sqla.orm.relationship('Location')
    type_id = sqla.Column(
        sqla.Integer,
        sqla.ForeignKey('weather_data_types.id'),
        nullable=False,
        primary_key=True
    )
    type = sqla.orm.relationship('WeatherDataTypes')
    value = sqla.Column(sqla.Float)

【问题讨论】:

【参考方案1】:

直接向 postgresql 发送请求帮助我了解发生了什么。

显然,当查询返回一列值和一列字符串时,Grafana 插件假定要绘制这些值,并且字符串列旨在用作绘图的标签。

我认为插件使用 groupby 来排序提取列以使其成为标签信息,但这种魔法不适用于两个字符串列,因为插件不会连接值本身。因此,插件抱怨第二个字符串列不是数字,这是一种误导,因为它不会抱怨第一个字符串列。

我可以通过将我用于 groupby 的值连接到单个列中来使其工作:

SELECT
  time_bucket('21600s',"timestamp") AS "time",
  avg(value),
  CONCAT(locations.name, ' ', weather_data_types.name) AS "name"
FROM weather_data
JOIN locations ON weather_data.location_id = locations.id
JOIN weather_data_types ON weather_data.type_id = weather_data_types.id
GROUP BY 1, locations.name, weather_data_types.name
ORDER BY 1

返回

          time          |        avg         |           name            
------------------------+--------------------+---------------------------

插件正确解释。

【讨论】:

以上是关于使用 Grafana 的(TimescaleDB)SQL 插件进行多连接的 Groupby 问题的主要内容,如果未能解决你的问题,请参考以下文章

时序数据库新手,从TimescaleDB for Grafana中选择数据速度慢,查询复杂

TimescaleDB 简单试用

快速入门:Java 连接使用 时序数据库 TimescaleDB

快速入门:Java 连接使用 时序数据库 TimescaleDB

timescaledb 集成 madlib

使用 postgres、timescaledb 获取时间戳至少在 5 分钟前的最新行