Слияние двух сложных запросов - PullRequest
1 голос
/ 22 июля 2010

В итоге я взял два 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()?

Ответы [ 2 ]

4 голосов
/ 22 июля 2010

Ну, вы всегда можете просто выполнить оба запроса:

$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 ...

РЕДАКТИРОВАТЬ: Теперь, когда я действительно посмотрю на это поближе, эти два запроса почти идентичны ... Почему бы просто не сделать что-то подобное (заменить предложение 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'] ... Так что вместо того, чтобы перечислить все перестановки, я просто выложил это как это ...

1 голос
/ 22 июля 2010

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

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 получает все строки от пользователейtable, и все строки из таблицы zebra, и ищет комбинации, которые удовлетворяют условию 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
...