2011-12-13 4 views
0

У меня есть 3 таблицыSQL: Получить последние записи из истории таблицы

person (id, name) 
area (id, number) 
history (id, person_id, area_id, type, datetime) 

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

тип истории = 'I' для CheckIn или 'O' для оформления заказа. Пример:

id person_id area_id type datetime 
1  2   5   'O'  '2011-12-01' 
2  2   5   'I'  '2011-12-31' 
A person started traveling in area 5 at 2011-12-01 and gave it back on 2011-12-31. 

Теперь я хочу, чтобы получить список всех областей все люди имеют прямо сейчас.

person1.name, area1.number, area2.number, area6.name 
person2.name, area5.number, area9.number 
.... 

Выход может быть, как это тоже (это не имеет значения):

person1.name, area1.number 
person1.name, area2.number 
person1.name, area6.number 
person2.name, area5.number 
.... 

Как я могу это сделать?

+0

Итак, вы ищете список людей, которые в настоящее время имеют выданную область и еще не проверили ее? – ean5533

+0

Я собираюсь лично рекомендовать против хранения 'type' в качестве значения' char' (или, по крайней мере, на его одиночестве) - сохранить его как ссылку fk на таблицу с подробным описанием того, что это значение _means_ (например, ваш 'person' и таблицы 'area'). Это ограничивает записи действительными значениями, которые могут (легко) быть обновлены в любое время, без необходимости в заявлениях 'alter' ... между прочим. –

+0

Предположительно, id = 1 во второй строке данных примера истории является опечаткой, и это должно быть 2 или какое-то другое число? –

ответ

1

Этот вопрос, на самом деле, довольно сложно. Вам нужен список записей в истории, где для данного пользователя и области есть запись «O» без последующей записи «I». Работа только с таблицей истории, что переводится как:

SELECT ho.person_id, ho.area_id, ho.type, MAX(ho.datetime) 
    FROM History AS ho 
WHERE ho.type = 'O' 
    AND NOT EXISTS(SELECT * 
        FROM History AS hi 
        WHERE hi.person_id = ho.person_id 
        AND hi.area_id = ho.area_id 
        AND hi.type = 'I' 
        AND hi.datetime > ho.datetime 
       ) 
GROUP BY ho.person_id, ho.area_id, ho.type; 

Тогда, так как вы на самом деле только после того, как имя человека и номер района (хотя, почему число площадь не может быть такой же, как его ID I я не уверен), вам нужно немного адаптироваться, вступив с дополнительными двумя столами:

SELECT p.name, a.number 
    FROM History AS ho 
    JOIN Person AS p ON ho.person_id = p.id 
    JOIN Area AS a ON ho.area_id = a.id 
WHERE ho.type = 'O' 
    AND NOT EXISTS(SELECT * 
        FROM History AS hi 
        WHERE hi.person_id = ho.person_id 
        AND hi.area_id = ho.area_id 
        AND hi.type = 'I' 
        AND hi.datetime > ho.datetime 
       ); 

функция нЕ СУЩЕСТВУЕТ оговорка коррелированный подзапрос; что имеет тенденцию быть неэффективным. Вы могли бы быть в состоянии переделать его как LEFT OUTER JOIN с соответствующим присоединиться и фильтровальным условием:

SELECT p.name, a.number 
    FROM History AS ho 
    JOIN Person AS p ON ho.person_id = p.id 
    JOIN Area AS a ON ho.area_id = a.id 
    LEFT OUTER JOIN History AS hi 
    ON hi.person_id = ho.person_id 
    AND hi.area_id = ho.area_id 
    AND hi.type = 'I' 
    AND hi.datetime > ho.datetime 
WHERE ho.type = 'O' 
    AND hi.person_id IS NULL; 

Всего SQL непроверенное.

0

Вы ищете результаты, в которых каждая строка может иметь различное количество столбцов? Я думаю, вы можете посмотреть в GROUP_CONCAT()

SELECT p.`id`, GROUP_CONCAT(a.`number`, ',') AS `areas` FROM `person` a LEFT JOIN `history` h ON h.`person_id` = p.`id` LEFT JOIN `area` a ON a.`id` = h.`area_id` 

Я не проверял этот запрос, но я использовал группу CONCAT подобным же образом раньше. Естественно, вы захотите адаптировать это в соответствии с вашими потребностями. Конечно, группа concat вернет строку, поэтому для использования данных потребуется пост-обработка.

EDIT У меня вопрос был изменен с тех пор, как я начал отвечать. Мой запрос не очень подходит ваш запрос больше ...

0

Попробуйте это:

select * 
from person p 
inner join history h on h.person_id = p.id 
left outer join history h2 on h2.person_id = p.id and h2.area_id = h.area_id and h2.type = 'O' 
inner join areas on a.id = h.area_id 
where h2.person_id is null and h.type = 'I' 
+0

Это не сработает, если человек однажды проверил область, проверил ее и снова проверил. ** Изменить: ** Возможно, добавление 'и h2.datetime> h.datetime' исправит эту проблему? Я еще не думал об этом. – ean5533

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