PostgreSQL: объединение двух таблиц по метке времени без двойного вхождения - PullRequest
0 голосов
/ 20 апреля 2020

Я ищу оператор PostgreSQL для соединения двух баз данных, однако простое объединение не делает то, что я хочу. Приведены две таблицы: одна - протоколирование печи (на основе регистрации температуры и состояния машины), другая - регистрация продуктов. Каждому продукту присваивается ровно один прогон печи, поэтому двойное присвоение одной строки продукта не должно выполняться.

печь

oven_id | runstart         | runend           | max_temp 
1       | 06.04.2020 19:33 | 06.04.2020 21:03 | 100        A
1       | 06.04.2020 23:28 | 07.04.2020 00:58 | 102        B
1       | 07.04.2020 10:00 | 07.04.2020 11:30 | 98         C
...

продукт

oven_id | oven_run | product_ids | preprocessing    | postprocessing
1       | 11100    | [1,4,6]     | 06.04.2020 12:44 | 06.04.2020 21:29     1
1       | 11101    | [2,3,7]     | 06.04.2020 19:24 | 07.04.2020 08:12     2
1       | 11102    | [5,8,9]     | 07.04.2020 05:31 | 07.04.2020 19:05     3
...

Мой первый подход:

select * 
from oven
left join product
    on oven.runstart>product.preprocessing and oven.runend<product.postprocessing and oven.oven_id=product.oven_id

Однако в некоторых конкретных c ситуациях (например, в примере выше) этот запрос не показывает желаемый результат, потому что я получить четыре строки (для простоты строки помечены AB C и 123 в приведенном выше примере): A-1, A-2, B-2 и C -3

https://www.db-fiddle.com/f/dBSGUE1nhvAkiZuGnL2nqs/3

Фактическая вещь, которую я ищу, - это назначение 1: 1 (каждый цикл духовки точно назначен одному продукту, никакой цикл духовки или продукт не используется дважды), поэтому каждый ряд духовки должен быть назначены на одну строку продукта. Учитывая приведенный выше пример, с логической точки зрения, комбинацией A-2 следует пренебречь, так как в противном случае один продукт будет дважды находиться в духовом шкафу (продукт 2 должен быть запущен B, поскольку в противном случае продукты не запускались бы в B).

Любая идея, как я могу настроить запрос, чтобы получать только три строки: A-1, B-2, C -3

Спасибо за вашу поддержку!

1 Ответ

0 голосов
/ 20 апреля 2020

Вы не сможете точно их сопоставить, у вас нет для этого необходимых данных.

F.ex. если у вас есть следующие настройки (где время на оси X):

<-- preprocessing 1 ---------------------------------- postprocessing 1 -->
   <-- preprocessing 2 -------------------------------- postprocessing 2 -->
      <-- runstart A --- runend A -->
                                      <-- runstart B -- runend B -->

Вы не можете действительно соединить только 1-A и 2-B. Если вы это сделаете, это просто догадка. Однако, если угадывание достаточно для вас, вы можете искать пары печь-продукт 1 к 1, например. с этим:

with recursive pairs(o, p) as (
  select * from (
    select oven, product
    from oven
    left join product
      on oven.oven_id = product.oven_id
      and tsrange(preprocessing, postprocessing) @> tsrange(runstart, runend)
    order by runstart
    limit 1
  ) as initial
  union all
  select * from (
    select oven, product
    from pairs, oven
    left join product
      on oven.oven_id = product.oven_id
      and tsrange(preprocessing, postprocessing) @> tsrange(runstart, runend)
    where (o) != oven -- use row-unique ID here, if you have
    and (o).runstart <= oven.runstart
    order by runstart
    limit 1
  ) as next
)
select (o).*, (p).*
from pairs

https://www.db-fiddle.com/f/3711YsHr3F5warVNaAB6LC/0

PS: это будет работать только с 1 oven_id. Если вам нужно собрать их для каждого oven_id одновременно, вам нужно будет также использовать некоторую агрегацию (но это сделает запрос слишком сложным, я не уверен, стоит ли оно усилий в этот момент).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...