2011-03-23 4 views
0

J'ai cette requête:Deux déclarations d'inscription

SELECT DISTINCT(b.friend_id) AS possible_id 
FROM friend_friends a 
    JOIN friends_friends b 
     ON b.user_id = a.friend_id 
WHERE a.user_id = 1703122278 

Il récupère les amis d'amis d'un utilisateur spécifique.

J'ai une autre base de données qui contient des données sur des personnes qui se sont déclarées PAS amis.

Voici la requête pour obtenir la liste des amis ne dit pas:

SELECT friend_id 
FROM friends_not_friends 
WHERE user_id = 1703122278 
AND not_friends = 1 

Ensuite, je compare la liste des amis non, de la liste d'amis possibles et supprimer les pas des amis de la liste.

Comment puis-je combiner ces deux requêtes sans utiliser de sous-requête mais plutôt en utilisant Joins?

+0

Qu'est-ce qui ne va pas avec l'utilisation de sous-requêtes? –

Répondre

3
SELECT DISTINCT(b.friend_id) AS possible_id 
FROM friend_friends a 
    JOIN friends_friends b 
    ON b.user_id = a.friend_id 
    LEFT JOIN friends_not_friends n 
    ON b.friend_id = n.friend_id 
     AND n.user_id = a.user_id 
     AND n.not_friends = 1 
WHERE a.user_id = 1703122278 
    AND n.friend_id IS NULL 

Cela montre la

(1st list of friends of friends of 1703122278) 
MINUS 
(2nd list of not friends of 1703122278) 

J'espère que vous n » t veulent le

list of friends of 
    (friends of 1703122278 
    minus 
    (2nd list of not friends of 1703122278) 
    ) 

Juste en trompant, voici les requêtes utilisant NOT IN. Personnellement, je les trouve plus clairs, mais ils peuvent être moins efficaces en termes de vitesse.

-- Friends of friends of a user 
SELECT DISTINCT(b.friend_id) AS possible_id 
FROM friend_friends b      -- the b and a aliases 
WHERE b.user_id IN       -- can be removed 
    (SELECT a.friend_id 
    FROM friends_friends a 
    WHERE a.user_id = 1703122278 
) 
; 

et a demandé un:

-- Friends of friends of a user that 
-- are also not not_friends of the user: 
SELECT DISTINCT(b.friend_id) AS possible_id 
FROM friend_friends b      -- the b, a and n aliases 
WHERE b.user_id IN       -- can be removed too 
    (SELECT a.friend_id 
    FROM friends_friends a 
    WHERE a.user_id = 1703122278 
) 
    AND b.friend_id NOT IN 
    (SELECT n.friend_id 
    FROM friends_not_friends n 
    WHERE n.user_id = 1703122278 
     AND n.not_friends = 1 
) 
; 
+0

Celui-ci a bien fonctionné. Seule chose a été modifiée AND n.user_id = 1703122278 à n.user_id = a.user_id. Simplifié un peu. Merci! – ehftwelve

+0

thnx. J'ai changé ma réponse aussi. S'il vous plaît vérifier que vous voulez ce que la requête donne et pas quelque chose comme 'liste d'amis de (amis moins notfriends)' –

1

en oracle je voudrais utiliser l'opérateur MINUS.

i Thik il y a une fonction correlary dans une base MySQL - probablement une jointure gauche ou non la clause

0

Essayez une jointure externe gauche à la table friend_not_friends (correspondant à friend_id, le filtrage sur user_id et le drapeau de not_friends) puis éliminer les lignes où il y avait une ligne correspondante de not_friends (qui est, d'éliminer les lignes où l'id not_friend est NOT NULL)

SELECT DISTINCT(f.friend_id) AS possible_id 
    FROM friend_friends a 
    JOIN friends_friends f 
    ON f.user_id = a.friend_id 
    LEFT 
    JOIN friends_not_friends n 
    ON n.user_id = a.user_id 
    AND n.friend_id = f.friend_id 
    AND n.not_friends = 1 
WHERE a.user_id = 1703122278 
    AND n.user_id IS NULL 

l'astuce est de filtrer les lignes qui correspondent, en laissant les lignes qui ne trouve pas match le tableau friends_not_friends. C'est le dernier prédicat de la requête (n.user_id IS NULL) qui effectue ce filtrage pour vous.


Absent l'obligation de ne pas utiliser une sous-requête, alors quelque chose comme ça fonctionnerait aussi bien:

SELECT DISTINCT(f.friend_id) AS possible_id 
    FROM friend_friends a 
    JOIN friends_friends f 
    ON f.user_id = a.friend_id 
    WHERE a.user_id = 1703122278 
    AND NOT EXISTS 
     (SELECT 1 
      FROM friends_not_friends n 
      WHERE n.friend_id = f.friend_id 
      AND n.user_id = a.user_id 
      AND n.not_friends = 1 
     ) 
1

Voici une solution qui filtre les « pas amis » sur tant au niveau (il filtre les non-amis de l'utilisateur et le sans but amis des amis de l'utilisateur):

SELECT 
    DISTINCT(b.friend_id) AS possible_id 
    FROM 
    friend_friends a 
    JOIN friend_friends b ON b.user_id = a.friend_id 
    LEFT JOIN friends_not_friends nfa 
     ON a.friend_id = nfa.user_id and nfa.not_friends = 1 
    LEFT JOIN friends_not_friends nfb 
     ON b.friend_id = nfb.user_id and nfb.not_friends = 1 
    WHERE 
    a.user_id = 1703122278 
    AND nfa.friend_id IS NULL 
    AND nfb.friend_id IS NULL 

le « truc » est de faire une LEFT JOIN et vérifier si i s aucune donnée (NULL).Par ailleurs - Y a-t-il une raison pour laquelle vous ne voulez pas de sous-sélection? Parfois, le LEFT JOIN -way est plus rapide, mais les sous-sélections sont souvent un bon choix.

+0

+1 pour vous dernier commentaire. J'ajouterais que (3ème option) une solution 'NOT IN' est généralement un code plus clair. –

Questions connexes