2016-10-07 2 views
-1

Я ищу способ получить записи в одном запросе sql для сложных объединений. У меня три таблицы позволяют говорить пользователям, user_projects и встречам. Пользователь может быть назначен нескольким проектам, и пользователь может иметь несколько встреч в разные даты. Как выбрать всех пользователей, назначенных для проектов1 и project2, и назначить встречи на дату1 и дату2? Я использую Postgres 9,5SQL-таблицы join

Образец данных:

users стол:

id, name  
1, Steve 
2, Bill 
3, Emma 

user_projects стол:

id, user_id, project_id 
1, 1, 1 
2, 2, 1 
3, 3, 1 
4, 1, 2 

appointments стол:

id, user_id, date 
1, 1, 2016-10-07 
2, 2, 2016-10-07 
3, 3, 2016-10-07 
4, 1, 2016-11-15 
5, 2, 2016-11-15 

Для этого специального случая можно сказать, что я хочу найти всех пользователей, принадлежащих проекту с идентификаторами 1 и 2, и назначить встречу на дату 2016-10-07 и 2016-11-15. И ожидаемый результат должен включать только пользователя с идентификатором 1, т.е. Стив в этом случае

+3

* Я ищу лучший способ * ... что означает, что у вас уже есть рабочий запрос. Можете ли вы опубликовать свой существующий SQL? Кроме того, какую базу данных вы используете? – sstan

+0

Я думаю, что это простое соединение ищут некоторые специальные –

+1

Как выглядит ваш запрос до сих пор? И какой вкус SQL это? –

ответ

0
SELECT ID 
FROM USERS U 
JOIN (
    -- Users in two projects 
    SELECT USER_ID 
    FROM USER_PROJECT 
    WHERE PROJECT_ID = 1 

    INTERSECTION 

    SELECT USER_ID 
    FROM USER_PROJECT 
    WHERE PROJECT_ID = 2 
) UP ON U.ID = UP.USER_ID 
JOIN (
    -- user ids that have appointments on two dates: 
    SELECT USER_ID 
    FROM APPOINTMENT 
    WHERE DATE = '2016-10-07' 

    INTERSECTION 

    SELECT USER_ID 
    FROM APPOINTMENT 
    WHERE DATE = '2016-11-15' 
) A ON U.ID = A.USER_ID 

Другой способ сделать это, что должно иметь такую ​​же производительность (может быть, это, кажется, лучше, потому что есть меньше строк):

SELECT ID 
FROM USERS U 
JOIN (
    -- Users in two projects 
    SELECT USER_ID 
    FROM USER_PROJECT 
    WHERE PROJECT_ID IN (1,2) 
    GROUP BY USER_ID 
    HAVING COUNT(DISTINCT PROJECT_ID) = 2 
) UP ON U.ID = UP.USER_ID 
JOIN (
    -- user ids that have appointments on two dates: 
    SELECT USER_ID 
    FROM APPOINTMENT 
    WHERE DATE IN ('2016-10-07','2016-11-15') 
    GROUP BY USER_ID 
    HAVING COUNT(DISTINCT DATE) = 2 
) A ON U.ID = A.USER_ID 
+1

Hogan, насколько масштабируемый этот запрос будет, если у меня есть миллион записей по каждой из приведенных выше таблиц – user2250206

+0

@ user2250206 - все будет хорошо, если вы поместите правильные индексы. Если у вас нет правильных индексов, ничего не будет «масштабируемо». Существует не более «эффективный» способ сделать это на основе правил, которые вы дали. Есть ли дополнительная информация о модели данных, которую мы можем использовать для повышения производительности? - если не так быстро, как это получится. – Hogan

+0

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

1

Может быть, я что-то недостающее вопрос. Похоже, просто присоединиться ко мне:

select distinct u.id 
from users u 
join user_projects up1 on u.id=up1.user_id 
join user_projects up2 on u.id=up2.user_id 
join appointments a1 on u.id=a1.user_id 
join appointments a2 on u.id=a2.user_id 
where up1.project_id = 1 
and up2.project_id = 2 
and a1.date = '2016-10-07' 
and a2.date = '2016-11-15' 

Вот скрипка: http://sqlfiddle.com/#!15/415fd/1/0