MySQL: логический запрос, возвращающий true, если пользователь не установил dnd или если пользователь установил dnd, данный идентификатор должен быть другом

У меня есть эти простые таблицы:

1. USER_DND
╔════════╦══════╗
║ UserID ║ DnD  ║
╠════════╬══════╣
╚════════╩══════╝

2. USER_FRIEND
╔════════╦══════════╗
║ UserID ║ FriendID ║
╠════════╬══════════╣
╚════════╩══════════╝

USER_DND: Содержит идентификаторы пользователей и их флаг "Не беспокоить" (Dnd). UserID является целым числом и является первичным ключом. DnD является логическим.

USER_FRIEND: Содержит идентификаторы друзей пользователей. UserID и FriendID оба являются целыми числами.

Проблема:

Для данных UserID и FriendID я хочу написать одиночный запрос, возвращающий логическое значение (SELECT CASE WHEN EXISTS), которое возвращает true в любом из случаев:

Если заданный UserID имеет DnD значение false в USER_DND

OR

Если заданный UserID имеет DnD значение true в USER_DND и данный FriendID существует в USER_FRIEND для этого UserID

Дополнительно:

Эти две таблицы с большим количеством строк. Запрос должен быть очень быстрым. Поэтому я не предпочитаю использовать OR в предложении where запроса или запрос с подзапросами. Оба имеют серьезные штрафы за производительность.


person Atul    schedule 26.06.2016    source источник
comment
Я не понимаю логики второго условия, оно не имеет особого смысла. FriendID существует только в USER_FRIEND, так как же этого не может быть?   -  person sagi    schedule 26.06.2016
comment
Как выглядит ваш SHOW CREATE TABLE для них? Ключом к производительности являются индексы.   -  person tadman    schedule 26.06.2016
comment
@sagi: Вопрос обновлен, чтобы сделать его более понятным. Пожалуйста, проверьте сейчас. Спасибо.   -  person Atul    schedule 26.06.2016
comment
@tadman: это переведено из больших таблиц, имеющих слишком много столбцов и индексов, для представления проблемы на SO. Как я уже сказал, USER_DND имеет первичный ключ, поэтому он сам является индексом, а в USER_FRIEND UserID индексируется.   -  person Atul    schedule 26.06.2016
comment
У вас есть индекс на обоих UserId, FriendID? Это очень важно при выполнении JOIN. Вот почему добавление схемы ваших таблиц, даже репрезентативной версии, очень важно, а диаграммы не очень помогают.   -  person tadman    schedule 26.06.2016
comment
@tadman: Да, точно, у меня есть индекс как для UserId, так и для FriendID   -  person Atul    schedule 26.06.2016


Ответы (1)


Вы можете попробовать использовать LEFT JOIN :

SELECT MAX(CASE WHEN ud.dnd = 'FALSE' THEN 'TRUE'
                WHEN uf.FriendID = YourGivenFriendID THEN 'TRUE'
                ELSE 'FALSE'
           END) as user_ind
FROM USER_DND ud
LEFT JOIN USER_FRIEND uf
 ON(ud.userID = uf.userID)
WHERE uf.userID = YourGivenID

Я предположил, что у каждого пользователя может быть несколько друзей, поэтому MAX() , если это 1-1 , вы можете удалить MAX()

person sagi    schedule 26.06.2016
comment
Шикарное решение :) - person Atul; 26.06.2016