Объединение таблиц, вычисляющих значения между датами

James Xiang спросил: 28 марта 2018 в 02:21 в: sql

, поэтому у меня есть две следующие таблицы

Таблица A

Date        num
01-16-15    10
02-20-15    12
03-20-15    13

Таблица B

Date        Value
01-02-15    100
01-03-15    101
   .         .
01-17-15    102
01-18-15    103
   .         .
02-22-15    104
   .         .
03-20-15    110

И Я хочу создать таблицу, которая имеет следующий вывод в impala

Date         Value
01-17-15     102*10
01-18-15     103*10
02-22-15     104*12
   .           .
   .           .

Итак, идея состоит в том, что мы рассматриваем только даты между 01-16-15 и 02-20-15, и 02-20-15 и 03-20-15. И используйте num начиная с даты начала этого периода, например, 01-16-15, и умножайте его на каждый день за период, т. Е. От 1-16 до 2-20.

Я понимаю, что это должно быть сделано by join, но я не уверен, как вы присоединяетесь к этому делу. Спасибо!

2 ответа

Gordon Linoff ответил: 28 марта 2018 в 03:03
Хммм. В стандартном SQL вы можете сделать следующее:
select b.*,
       (select a.num
        from a
        where a.date <= b.date
        order by a.date desc
        fetch first 1 row only
       ) * value as new_value
from b;

Я не думаю, что это соответствует условиям диапазона, но я не понимаю вашего описания этого.

Я также не знаю, поддерживает ли Impala коррелированные подзапросы. Альтернатива, вероятно, быстрее для сложных данных:

with ab as (
      select a.date, a.value as a_value, null as b_value, 'a' as which
      from a
      union all
      select b.date, null as a_value, b_value, 'b' as which
      from b
     )
select date, b_value * a_real_value
from (select ab.*,
             max(a_value) over (partition by a_date) as a_real_value
      from (select ab.*,
                   max(a.date) over (order by date, which) as a_date
            from ab
           ) ab
     ) ab
where which = 'b';
Joakim Danielson ответил: 28 марта 2018 в 05:29

Это работает на MariaDb (MySql) и довольно простое, так что, надеюсь, оно работает и на Impala.

SELECT b.date, b.value * a.num
FROM tableB b, tableA a
WHERE b.date >= a.date
  AND (b.date < (SELECT MIN(c.date) FROM tableA c WHERE c.date > a.date)
       OR NOT EXISTS(SELECT c.date FROM tableA c WHERE c.date > a.date))

Последнее НЕ СУЩЕСТВУЕТ ... было необходимо, чтобы включить даты после последняя дата в таблице A

Update В пересмотренной версии вопроса дата в B никогда не бывает больше (после) последней даты в A, поэтому запрос можно записать в виде

SELECT b.date, b.value * a.num
FROM tableB b, tableA a
WHERE b.date >= a.date
  AND b.date <= (SELECT MIN(c.date) FROM tableA c WHERE c.date > a.date)
James Xiang ответил: 28 марта 2018 в 03:42
Можете ли вы объяснить помет больше о функции И здесь? А также в опечатке есть опечатка, и я уже исправил ее. По сути, последние даты двух таблиц одинаковы, в этом случае нам не нужно предложение NOT EXISTS, верно?
Joakim Danielson ответил: 28 марта 2018 в 03:45
"условие1 И условие2" это означает, что оба условия должны быть выполнены. Таким образом, здесь это означает, что b.date должно быть > = дата из A и меньше, чем следующая дата в таблице A
James Xiang ответил: 28 марта 2018 в 03:54
Таким образом, для пересмотренной версии, где последняя дата одинакова для обеих таблиц, нам нужно только право AND (b.date < (ВЫБРАТЬ МИНУТ (c.date)) из таблицыA c ГДЕ c.date > a.date)?
Joakim Danielson ответил: 28 марта 2018 в 04:22
Нет, вам все равно понадобится полный текст предложения WHERE из моего ответа
James Xiang ответил: 28 марта 2018 в 04:55
ХОРОШО. Только что попробовал в impala и возвращает ошибку: подзапросы в предикатах OR не поддерживаются. Есть идеи, что здесь происходит?