Создайте несколько строк на основе одной строки, содержащей нулевое значение после правильного соединения

#sql #postgresql #right-join

#sql #postgresql #соединение справа

Вопрос:

У меня есть программное обеспечение, которое извлекает данные с нескольких устройств с помощью SNMP. Затем программное обеспечение создает запись в таблице с начальным временем опроса и временем окончания опроса.

Для каждой извлекаемой нами таблицы SNMP мы помещаем данные в разные таблицы.

В приведенной ниже модели имеется одна таблица snmp (FrequencyValue). Таблицы выглядят следующим образом:

 | Polls |                  |                  |
|-------|------------------|------------------|
| id    | start_time       | end_time         |
|-------|------------------|------------------|
| 1     | 2019-04-01T10:00 | 2019-04-01T10:10 |
| 2     | 2019-04-01T11:00 | 2019-04-01T11:10 |
| 3     | 2019-04-01T12:00 | 2019-04-01T12:10 |

| Devices    |
|------------|
| ip         |
|------------|
| 172.16.1.1 |

| FrequencyValue |         |                  |           |       |
|----------------|---------|------------------|-----------|-------|
|      device_ip | poll_id | timestamp        | frequency | value |
|----------------|---------|------------------|-----------|-------|
|     172.16.1.1 |       1 | 2019-04-01T10:02 |      1000 |    10 |
|     172.16.1.1 |       1 | 2019-04-01T10:02 |      2000 |    20 |
|                |         |                  |           |       |
|     172.16.1.1 |       3 | 2019-04-01T12:02 |      1000 |    10 |
|     172.16.1.1 |       3 | 2019-04-01T12:02 |      2000 |    20 |

  

Проблема возникает, когда устройство не отвечает, потому что, как показано в таблице FrequencyValue , программное обеспечение не создало запись для этой таблицы.

Вопрос: Для того, чтобы отобразить столбец value на frequency , мы хотели бы создать n строки для каждой frequency , в которых был бы столбец value to null .

Пока что наш запрос выглядит следующим образом:

 select p.ip, coalesce(t.timestamp, p.start_time) as "time", t.frequency, t.value
from FrequencyValue as t
right join (
  select p.start_time, p.id, d.ip
  from Polls as p, Devices as d
) as p on (t.poll_id = p.id and t.device_ip = p.ip)
  

С выводом:

 |         ip | timestamp        | frequency | value |
|------------|------------------|-----------|-------|
| 172.16.1.1 | 2019-04-01T10:02 |      1000 |    10 |
| 172.16.1.1 | 2019-04-01T10:02 |      2000 |    20 |
|            |                  |           |       |
| 172.16.1.1 | 2019-04-01T11:00 |      null |  null |
|            |                  |           |       |
| 172.16.1.1 | 2019-04-01T12:02 |      1000 |    10 |
| 172.16.1.1 | 2019-04-01T12:02 |      2000 |    20 |
  

Что мы на самом деле хотим, так это:

 |         ip | timestamp        | frequency | value |
|------------|------------------|-----------|-------|
| 172.16.1.1 | 2019-04-01T10:02 |      1000 |    10 |
| 172.16.1.1 | 2019-04-01T10:02 |      2000 |    20 |
|            |                  |           |       |
| 172.16.1.1 | 2019-04-01T11:00 |      1000 |  null |
| 172.16.1.1 | 2019-04-01T11:00 |      2000 |  null |
|            |                  |           |       |
| 172.16.1.1 | 2019-04-01T12:02 |      1000 |    10 |
| 172.16.1.1 | 2019-04-01T12:02 |      2000 |    20 |
  

Мы пытались ввести другое соединение справа в запрос, но мы просто не можем получить желаемый результат.
Частоты нигде не определены, поэтому для извлечения доступных частот мы могли бы select distinct использовать частоты в таблице.
База данных — это PostgreSQL.

Ответ №1:

Используйте a cross join для генерации строк, а затем a left join для ввода значений:

 select d.ip, t.timestamp, f.frequency,  fv.value
from devices d cross join
     (select distinct timestamp from frequencyvalue) t cross join
     (select distinct frequency from frequencyvalue) f left join
     frequencyvalue fv
     on fv.device_ip = d.ip and
        fv.timestamp = t.timestamp and
        fv.frequency = f.frequency;