Проблема Groupby при множественном объединении с использованием плагина Grafana (TimescaleDB) SQL

#sql #postgresql #grafana #timescaledb

#sql #postgresql #grafana #timescaledb

Вопрос:

Я использую SQL-плагин Grafana для запроса базы данных TimescaleDB.

БД хранит информацию о погоде в виде

 | timestamp | location_id | data_type_id | value |
 

где location_id и data_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, потому что он не может отображать строки.

Изменение этого параметра на возврат (целого) идентификатора вместо этого удаляет сообщение об ошибке

 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
 

но отображаются две серии: avg и id , которые показывают, что тип 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 предполагает, что значения должны быть отображены, а столбец string предназначен для использования в качестве меток для графиков.

Я думал, что плагин использовал 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            
------------------------ -------------------- ---------------------------
 

который правильно интерпретируется плагином.