2016-08-10 3 views
0

Хорошо, так что я застрял на этом в течение 2 дней! Я решил это с семантической точки зрения, но запрос может занять до 10 минут. Моя база данных для этого - SQLite (по причинам, которые я не хочу здесь останавливаться), но я попытался выполнить одно и то же на SQL Server 2012, это не сильно повлияло на производительность.SQL Join Challenge

Таким образом, проблема заключается в том, что у меня есть 2 таблицы

  • prices (product_id INT, for_date DATE, значение INT)
  • events (starts_on ДАТА, ends_on ДАТА NULLABLE)

I имеют примерно 500 тыс. строк в таблице цен и около 100 строк в таблице событий.

Теперь мне нужно написать запрос, чтобы сделать следующее.

псевдокод является:

  • Для каждого события:
    • Если событие имеет значение ends_on ТОГДА выборки все product_id (ы), которые имеют соответствующий for_date, Для продуктов, которые не совпадают, то введите последнее значение for_date, которое меньше значения end_on, но больше, чем start_on для этого события.
    • ELSE Если end_on дата события NULL, THEN выберете все product_id (ы), у которых есть значение for_date, которое соответствует start_on, для продуктов, для которых NOT MATCH выбрано последнее значение for_date, которое меньше значения start_on.

Запрос я написал в SQL Server 2012 является

SELECT  
    sp.for_date, sp.value 
FROM 
    prices sp 
INNER JOIN 
    events ev ON (((ev.ends_on IS NOT NULL AND 
        (sp.for_date = (SELECT for_date 
            FROM prices 
            WHERE for_date <= ev.ends_on 
             AND for_date > ev.starts_on 
            ORDER BY for_date DESC 
             OFFSET 0 ROWS 
             FETCH NEXT 1 ROWS ONLY)))) 
      OR 
      ((ev.ends_on is null 
      and 
      (sp.for_date = (SELECT for_date 
           FROM prices 
           WHERE 
            for_date <= ev.starts_on_j 
            AND for_date > dateadd(day, -14, ev.starts_on) 
           order by for_date desc 
           offset 0 rows 
            fetch next 1 row only)))) 

            ); 

Btw Я также пытался создать временные таблицы с частичными данными и сделать то же оп на них. Он просто застревает.

Странная вещь, если я запускаю 2 "ИЛИ" условия отдельно, время отклика идеально!

Update

Образец Dataset и ожидаемый результат

Цена Записи

Product ID, ForDt, Value 
1, 25-01-2010, 123 
1, 26-01-2010, 112 
1, 29-01-2010, 334 
1, 02-02-2010, 512 
1, 03-02-2010, 765 
1, 04-02-2010, 632 
1, 05-02-2010, 311 
1, 06-02-2010, 555 
2, 03-02-2010, 854 
2, 04-02-2010, 625 
2, 05-02-2010, 919 
3, 20-01-2010, 777 
3, 06-02-2010, 877 
3, 10-03-2010, 444 
3, 11-03-2010, 888 

событий Записи (Для того, чтобы сделать его более понятным, Im добавляя идентификатор события также)

Event ID, StartsOn, EndsOn 
22, 27-01-2010, NULL 
33, 02-02-2010, 06-02-2010 
44, 01-03-2010, 13-03-2010 

Ожидаемый результат Установите

Event ID, Product ID, ForDt, Value 
22, 1, 26-01-2010, 112 
33, 1, 06-02-2010, 311 
44, 1, 06-02-2010, 311 

33, 2, 05-02-2010, 919 
44, 2, 05-02-2010, 919 

22, 3, 20-01-2010, 777 
33, 3, 06-02-2010, 877 
44, 3, 11-03-2010, 888 
+0

Если вы можете показать запрос и выход, это будет полезно, чтобы понять, что запрос делает – TheGameiswar

+0

также показывают индексы и как те выше две таблицы, связанные с некоторыми данными sampe – TheGameiswar

+1

И вывод [РАЗМЕРЫ ЗАПРОСА] (http://www.sqlite.org/eqp.html). –

ответ

1

Хорошо, теперь, когда вы показали ожидаемые результаты быть список событий и связанных с ними продуктов, вопрос имеет смысл. Ваш запрос только для выбора дат и значений не сделал.

Вы ищете лучшую цену за товар для каждого события. Это легко сделать с аналитическими функциями, но SQLite их не поддерживает. Поэтому мы должны написать более сложный запрос.

Давайте рассмотрим события с ends_on null. Вот как найти лучшие цены на продукцию (т.е. последний перед starts_on):

select e.event_id, p.product_id, max(for_date) as best_for_date 
from events e 
join prices p on p.for_date < e.starts_on 
where e.ends_on is null 
group by e.event_id, p.product_id; 

Продолжим этот запрос также найти лучшие цены на продукцию для событий с ends_on, а затем получить доступ к таблице продуктов снова, таким образом, мы получаем полные записи со значениями:

select ep.event_id, p.product_id, p.for_date, p.value 
from 
(
    select e.event_id, p.product_id, max(for_date) as best_for_date 
    from events e 
    join prices p on (e.ends_on is null and p.for_date < e.starts_on) 
       or (e.ends_on is not null and p.for_date between e.starts_on and e.ends_on) 
    group by e.event_id, p.product_id 
) ep 
join prices p on p.product_id = ep.product_id and p.for_date = ep.best_for_date; 

(Кстати:. Вы описываете очень частный случай здесь базы данных, которые я видел до сих пор было лечить ends_onnull, как неограниченный или «по-прежнему активны» таким образом, цена. для извлечения для такого события не будет последним перед темstarts_on, но самый текущий на или послеstarts_on.)

+0

Итак, я думаю, что этот запрос в основном работает, попробует его в разных комбинациях моего основного производственного набора данных. На данный момент я заменил p.for_date Storm

+0

Спасибо Thorsten. Мне было неловко не использовать max в предложении select: o) – Storm