2016-09-22 5 views
1

Я хочу присоединиться к двум таблицам, сопоставляя время в одной таблице с периодом (время начала и окончания) на втором, и мне нужно сделать это, чтобы операция сохраняла точную информацию в одной таблице. В частности, у меня есть эти таблицы.Как присоединиться к таблицам, сохраняя точную информацию в одной таблице?

Таблица t1:

cid time1 
A  2016-01-05 11:00:00 
A  2016-01-15 11:00:00 
A  2016-01-25 11:00:00 
B  2016-01-09 11:00:00 

Таблица t2:

cid period_start   period_end 
A  2016-01-01 00:00:00 2016-01-10 00:00:00 
A  2016-01-10 00:00:00 2016-01-16 00:00:00 
A  2016-01-12 00:00:00 2016-01-20 00:00:00 

И я хочу, вывод как:

cid time1     period_start   period_end 
A  2016-01-05 11:00:00 2016-01-01 00:00:00 2016-01-10 00:00:00 
A  2016-01-15 11:00:00 2016-01-10 00:00:00 2016-01-16 00:00:00 
A  2016-01-25 11:00:00 NULL     NULL 
B  2016-01-09 11:00:00 NULL     NULL 

Несколько Дополнительная информация/условия:

  • Я хочу, чтобы информация о t1 была сохранена точно на выходе (например, никакие строки на t1 не объединены с несколькими строками на t2, ни строк из t1, отсутствующих на выходе). Другими словами, мне просто нужна информация от t2, добавленная к t1 в виде столбцов.
  • Если в t2 нет периода, который включает time1 в t1, я хочу, чтобы period_start и period_end были NULL.
  • Также может отсутствовать соответствующий cid на t2.
  • Если на t2 имеется несколько совпадений, я хочу только первый.

Прямо сейчас у меня есть:

SELECT t1.*, t2.period_start, t2.period_end 
FROM t1 
    LEFT JOIN t2 ON t1.cid = t2.cid 
WHERE t2.period_start >= t1.time1 
AND t2.period_end <= t1.time1 

, но это не правильно обрабатывать ситуацию, в которой нет никакого совпадения. Как я могу это сделать?

Я делаю это на Redshift.

ответ

1

Поскольку вы хотите только первую найденную строку из t2, вы могли бы использовать LATERAL подзапрос с LIMIT пункта:

SELECT t1.cid, t1.time1, t2.period_start, t2.period_end 
FROM t1 LEFT JOIN LATERAL 
    (SELECT * 
     FROM t2 
     WHERE cid=t1.cid AND t1.time1 BETWEEN period_start AND period_end 
     ORDER BY t2.period_start 
     LIMIT 1 
    ) t2 ON true 
+0

Удивительный, спасибо! –

1

Перенесите фильтры t2 из ИНЕК джоен

FROM t1 LEFT JOIN t2 ep ON t1.cid = t2.cid 
and t2.period_start >= t1.time1 
AND t2.period_end <= t1.time1 

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

+0

Это не работает для меня, потому что 15 января в t1 получает присоединился к двум строкам в t2. Мне нужен только первый. –

1

Вы можете использовать следующий запрос:

SELECT cid, time1, period_start, period_end 
FROM (
    SELECT t1.cid, t1.time1, t2.period_start, t2.period_end, 
      ROW_NUMBER() OVER (PARTITION BY t1.cid, t1.time1 
          ORDER BY t2.period_start) AS rn 
    FROM t1 
    LEFT JOIN t2 ON t1.cid = t2.cid AND 
        t1.time1 BETWEEN t2.period_start AND t2.period_end) AS t 
WHERE t.rn = 1    

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

+0

Удивительный, спасибо! –

Смежные вопросы