2

У меня есть следующие структуры таблицы:SQL присоединиться к коррелированных подзапросов, где таблицы связаны с помощью перекрывающихся диапазонов

Пункт

ID | Name 
-------- 
1 | Apple 
2 | Pear 
3 | Banana 
4 | Plum 
5 | Tomato 

событий

ItemStart | ItemEnd | EventType | EventDate 
-------------------------------------------- 
    1 | 2 | Planted | 2014-01-01 
    1 | 3 | Picked | 2014-01-02 
    3 | 5 | Eaten | 2014-01-05 

две таблицы связанный только с первичным ключом Item и диапазоном ItemStart и ItemEnd (включительно) в событии. События всегда относятся к смежным последовательностям элементов, но не все события для данного элемента будут иметь одинаковый диапазон. События никогда не появляются в тот же день для данного элемента.

Запрос Я хотел бы производить следующим образом: выход

List all the Items, and for each Item show the most recent Event

Пример:

ID | Name | Event | Date 
---------------------------- 
1 | Apple | Picked | 2014-01-02 (Planted then Picked) 
2 | Pear | Picked | 2014-01-02 (Planted then Picked) 
3 | Banana | Eaten | 2014-01-05 (Picked then Eaten) 
4 | Plum | Eaten | 2014-01-05 (Eaten) 
5 | Tomato | Eaten | 2014-01-05 (Eaten) 

Это кажется достаточно разумным, на лице его, и если там были традиционными отношения внешнего ключа на месте (представьте ItemID вместо ItemStart и ItemEnd). Я бы, вероятно, присоединился к коррелированному подзапросу примерно так:

SELECT Name, EventType, EventDate 
FROM Item i 
    INNER JOIN (
     SELECT ItemID, EventType, EventDate 
     FROM Event e 
     WHERE EventDate = (SELECT MAX(EventDate) FROM Event e_max WHERE e_max.ItemID = e.ItemID) 
    ) latest_events ON i.ID = latest_events.ItemID 

Однако, с отношением расстояния в месте я застрял, я хочу сделать что-то больше похоже на это, но он не работает:

SELECT Name, EventType, EventDate 
FROM Item i 
    INNER JOIN (
     SELECT ItemStart, ItemEnd, EventType, EventDate 
     FROM Event e 
     WHERE EventDate = (SELECT MAX(EventDate) FROM Event e_max WHERE i.ID >= e_max.ItemStart AND i.ID <= e_max.ItemEnd) 
    ) latest_events ON i.ID >= latest_events.ItemStart AND i.ID <= latest_events.ItemEnd 

Я получаю ошибку о i.ID >= e_max.ItemStart AND i.ID <= e_max.ItemEnd в строке 6 , потому что вы не можете ссылаться на i из другой части соединения. Я хотел сделать это (что не обязательно в более простом примере), потому что, когда я создаю подзапрос, у меня больше нет единого идентификатора для ссылки - перекрывающиеся диапазоны означают, что существует много возможных способов включения одного элемента , и поэтому я хочу обратиться непосредственно к этому элементу, чей идентификатор доступен только в таблице позиций верхнего уровня.

Надеюсь, это имеет смысл.

Я использую SQL Server 2008 R2. Это для отчета, который будет работать в одночасье, поэтому скорость не такая важная, как это может быть, но очень много предметов (100 миллионов); в то время как есть несколько событий против каждого элемента, использование больших диапазонов означает, что записей событий намного меньше.

Вещи я думал:

  • Каким-то образом расширяется из отношения Пункт/событие, так что события записываются против всех отдельных предметов. Это приведет к значительному увеличению объема рассматриваемых данных, но позволит упростить подход к поиску.
  • Как-то обрабатывать события, чтобы ограничить или объединить диапазоны - если бы я знал, что для данного элемента все его События имели одинаковое начало и конец, я мог бы упростить вещи. Не все так хорошо.

Как я могу произвести этот запрос? Заранее спасибо!

+0

Я не уверен, если я понял, так как я не мог следовать вашему ожидается пример вывода. Может быть, вы могли бы присоединиться к нему более traditionaly с помощью представления 'CREATE VIEW V_EVENT в Выберите ItemStart как Item, EventType, EVENTDATE UNION Выберите ItemEnd, EventType, EVENTDATE ' – bummi

+0

возможно дубликат [SQL - Нахождение максимальной группы дат таблицей идентификаторов ] (http://stackoverflow.com/questions/25529320/sql-finding-the-maximum-date-group-by-id-table) – Bulat

ответ

3

Вы можете сделать это, используя CTE и row_number().

SQL Fiddle Demo

;with cte as 
(
    SELECT *, 
     ROW_NUMBER() OVER (PARTITION BY i.id ORDER BY e.EventDate DESC) as rNum 
    FROM Item i 
    JOIN Event e 
     ON i.id between e.ItemStart and e.ItemEnd 
) 

SELECT ID, 
    Name, 
    EventType, 
    EventDate FROM cte 
WHERE rNum = 1 

В основном КТР присоединился деталь и событие, и добавлен новый столбец для RowNumber и разделена на item.ID. Вот скриншот того, как он выглядит. Отсюда я просто выбираю rNum = 1, который должен быть максимальной датой события для каждого элемента.

enter image description here

1

Это должно быть подобно другим величайшей-в-группы и присоединяющихся-на-диапазона решений:

SELECT * FROM 
    Item i INNER JOIN 
    Event e ON i.id BETWEEN e.ItemStart AND e.ItemEnd 
WHERE NOT EXISTS (-- exclude non-last events 
    SELECT * FROM Event 
    WHERE 
     i.id between ItemStart and ItemEnd 
     AND e.EventDate < EventDate) 
+0

Просто попробовал это в SQLFiddle от @JChao, и это не совсем дает правильный результат (не возвращает все элементы). Я не уверен, что понимаю, как это нужно для работы достаточно, чтобы исправить это, вы можете что-нибудь увидеть? – frumious

+0

Я его обновил, работает для меня – Bulat

+0

http://sqlfiddle.com/#!3/de664/8 – Bulat