2010-07-21 3 views
1

То, что я в конечном итоге делает принимает два запроса SQL и с помощью array_intersect() в PHP, чтобы отфильтровать результаты:Объединение двух сложных запросов

$sql1 = 'SELECT z.*, u.username, u.user_colour, u.username_clean, u.user_avatar, u.user_avatar_type 
    FROM ' . ZEBRA_TABLE . ' z, ' . USERS_TABLE . ' u 
    WHERE ((z.user_id = ' . $user->data['user_id'] . ' 
     AND z.friend = 1 
     AND u.user_id = z.zebra_id) 
      OR (z.zebra_id = ' . $user->data['user_id'] . ' 
       AND z.friend = 1 
       AND u.user_id = z.user_id)) 
    ORDER BY u.username_clean ASC'; 

$sql2 = 'SELECT z.*, u.username, u.user_colour, u.username_clean, u.user_avatar, u.user_avatar_type 
    FROM ' . ZEBRA_TABLE . ' z, ' . USERS_TABLE . ' u 
    WHERE ((z.user_id = ' . $user_id . ' 
     AND z.friend = 1 
     AND u.user_id = z.zebra_id) 
      OR (z.zebra_id = ' . $user_id . ' 
       AND z.friend = 1 
       AND u.user_id = z.user_id)) 
    ORDER BY u.username_clean ASC'; 

Структура обоих запросов одинаковы и разница лишь в том $user->data['user_id] (первое лицо) заменяется на $user_id (второе лицо) во втором запросе. Я хочу, чтобы друзья, которых у обоих пользователей есть, есть. Может ли кто-нибудь объединить это в один запрос, чтобы мне не пришлось использовать два запроса и вызывать array_intersect()?

+1

Какой вкус SQL ты используешь? Поддерживает ли он оператор INTERSECT? – FrustratedWithFormsDesigner

+0

MySQL. Я никогда не знал об операторе INTERSECT. –

+1

Обычная таблица отношений «многие-ко-многим» с двумя (или несколькими элементами): см. Http://stackoverflow.com/questions/477006/sql-statement-join-vs-group-by-and-having/477013 # 477013 – Wrikken

ответ

4

Ну, вы всегда можете просто подзапрос как:

$sql = 'SELECT a.* 
    FROM ('.$sql1.') AS a 
    JOIN ('.$sql2.') AS b ON a.user_id = b.user_id AND a.username = b.username'; 

Вы можете добавить u.user_id к списку полей обоих запросов u.user_id AS u_user_id затем изменить второй пункт присоединиться от a.username = b.username к a.u_user_id = b.u_user_id ...

EDIT: Теперь, когда я действительно смотрю на него ближе, эти два вопроса почти идентичны ... Почему бы просто не сделать что-то вроде этого (замените предложение where на это):

WHERE z.friend = 1 
    AND (
     (z.user_id = '.$user_id.' AND u.user_id = z.zebra_id) 
     OR 
     (z.zebra_id = '.$user_id.' AND u.user_id = z.user_id) 
    ) AND (
     (z.user_id = '.$user->data['user_id'].' AND u.user_id = z.zebra_id) 
     OR 
     (z.zebra_id = '.$user->data['user_id'].' AND u.user_id = z.user_id) 
    ) 

Это должно дать вам результат обоих запросов пересекались, и быстрее, так как он может оптимизировать лучше (надеюсь) ...

О, и они находятся в разных, где блоки, потому что есть несколько случаев, когда z.user_id соответствует $user_id, но z.zebra_id соответствует $user->data['user_id'] ... Так, а не список всех перестановок, я просто укладывать его, как это ...

+0

+1 Это, вероятно, вариант * лучше *, поскольку не все атрибуты SQL имеют 'INTERSECT' –

+0

Благодаря ircmaxell, это то, что я искал. Я новичок в базах данных, и вы, вероятно, видите, что мои SQL-запросы становятся очень неаккуратными. –

+0

Я должен указать - это не объединяет два запроса в 1 запрос, он объединяет их в 3 запроса.Кроме того - замена 'WHERE' не похожа на работу. Таблица 'z' не может содержать' (u.user_id, @ friend_id1) 'AND' (u.user_id, @ friend_id2) 'в одной строке, вам нужно будет добавить вторую ссылку на таблицу' z' – gnarf

1

Вы можете выбрать пользователей, которые дружат с обоими пользователями, связав таблицу пользователей зебры таблица дважды:

SELECT u.username, u.user_colour, u.username_clean, u.user_avatar, u.user_avatar_type 
FROM users u 
JOIN zebra z1 ON z1.friend=1 AND (
        (u.user_id = z1.user_id AND z1.zebra_id = @user_id1) 
        OR (u.user_id = z1.zebra_id AND z1.user_id = @user_id1) 
       ) 
JOIN zebra z2 ON z2.friend=1 AND (
        (u.user_id = z2.user_id AND z2.zebra_id = @user_id2) 
        OR (u.user_id = z2.zebra_id AND z2.user_id = @user_id2) 
       ) 
ORDER BY u.username_clean ASC 

JOIN берет все строки из таблицы пользователей и все строки из таблицы зебры и ищет комбинации, которые удовлетворяют условию ON. В этом случае первое соединение находит всех пользователей, которые являются друзьями с @user_id1, второе соединение дополнительно ограничивает его для пользователей, которые также являются друзьями с @user_id2.

Этот запрос будет выполняться намного быстрее, чем использование подзапросов. Запрос будет еще быстрее, если zebra таблица хранится дружеские в обоих направлениях, что позволяет принимать более преимущество индексов таблицы, и вы можете удалить OR часть ON статей:

SELECT u.username, u.user_colour, u.username_clean, u.user_avatar, u.user_avatar_type 
FROM users u 
JOIN zebra z1 ON u.user_id = z1.user_id AND z1.friend=1 AND z1.zebra_id = @user_id1 
JOIN zebra z2 ON u.user_id = z2.user_id AND z2.friend=1 AND z2.zebra_id = @user_id2 
ORDER BY u.username_clean ASC 
Смежные вопросы