2013-07-29 4 views
1

У меня есть таблица подписки на контакты. Контакт может иметь несколько подписок:Сравните даты начала и окончания нескольких строк

CREATE TABLE contact (
    id INTEGER NOT NULL, 
    name TEXT, 
    PRIMARY KEY (id) 
); 

CREATE TABLE subscription (
    id INTEGER NOT NULL, 
    contact_id INTEGER NOT NULL REFERENCES contact(id), 
    start_date DATE, 
    end_date DATE, 
    PRIMARY KEY (id) 
); 

Мне нужно получить все подписки для данного при контакте, что делать не иметь подписку , которая начинается на ту же дату, что и дата окончания другой подписки на такой же связь.

Так что для приведенных данных:

INSERT INTO contact (id, name) VALUES 
(1, 'John'), 
(2, 'Frank'); 

INSERT INTO subscription (id, contact_id, start_date, end_date) VALUES 
(1, 1, '2012-01-01', '2013-01-01'), 
(2, 1, '2013-01-01', '2014-01-01'), 
(3, 2, '2012-01-01', '2012-09-01'), 
(4, 2, '2013-01-01', '2014-01-01'); 

Я хочу, чтобы получить подписку с идентификаторами 2, 3, 4, но не 1, потому что контакт «John» имеет подписку с start_date на том же день (2013-01-01) в качестве end_date для подписки с id из 1.

Что является лучшим способом для достижения этой цели?

+1

Исправлена ​​опечатка, но мне нравится, как вы предоставили правильный тестовый пример. +1 Обратите внимание, однако, что ваш текст противоречит самому себе. Запрос 'для данного контакта' никогда не может возвращать' 2, 3, 4', так как '2' принадлежит отдельному контакту. –

ответ

1

SQL Fiddle

select * 
from subscription s0 
where not exists (
    select 1 
    from subscription s1 
    where 
     s0.contact_id = s1.contact_id 
     and s1.start_date = s0.end_date 
) 
order by contact_id, id 
+0

Возможно, я не был достаточно исчерпывающим в данных примера в моем вопросе, но, насколько я могу судить, это решение не будет работать, если на один контакт больше двух подписчиков. Смотрите это [скрипка] (http://sqlfiddle.com/#!12/dffb3/1/0). – Divey

+0

@ Divey I [обновил скрипку] (http://sqlfiddle.com/#!12/55e67/1) с более чем двумя подписками на контакт. Опубликуйте больше данных, чтобы проверить его. –

+0

Используя вашу скрипку, подписка с идентификатором 4 не должна появляться в результатах. Он имеет значение end_date из «2014-01-01», которое является стартовым знаком для следующей подписки (id 5). – Divey

0

LEFT JOIN/IS NULL должен быть хорошим выбором, так как там обычно нет (или мало) строк, чтобы присоединиться:

SELECT * 
FROM subscription s 
LEFT JOIN subscription s1 ON s1.contact_id = s.contact_id 
          AND s1.start_date = s.end_date 
WHERE s.contact_id = 1 
AND s1.id IS NULL; 

->SQLfiddle

Хорошо работает с Postgres 8.4.
Но вариант NOT EXISTS @ Clodoaldo должен быть хорошим, просто добавьте WHERE пункт for a given contact.

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