2010-02-19 13 views
8

Tengo este problema. Dada una tabla users que consta de nombre de usuario de los usuarios en una red social y friends tabla que contiene el nombre de un usuario y FRIENDNAME de un usuario, como a continuación ...Oracle SQL cómo escribir una declaración sql que comprueba si el usuario en mi red (es decir, amigos o amigos de amigos)

username friendname 

John  Thomas 
Chris  James 

... Estoy tratando de escribir una instrucción SQL eso lo hará si un usuario está en mi red. En otras palabras, es ese usuario un amigo o amigo de amigos?

he estado bailando en torno a este problema y sólo podía llegar a esta consulta:

SELECT f2.username, f2.friendname 
FROM friends f2 
WHERE f2.username IN (
     SELECT f1.friendname 
     FROM friends f1 
     WHERE f1.username = 'Thomas') 
AND f2.friendname <> 'user1' 
AND f2.friendname = 'user2';  

Básicamente comprobar si un usuario si es un amigo de mi amigo es decir, simplemente devuelve null si es falso.

Tratando de averiguar cómo puedo expandirme para revisar toda mi red de amigos. Quiero decir no solo amigo de mi amigo.

Respuesta

5
SELECT * 
FROM (
     SELECT username 
     FROM friends 
     START WITH 
       username = 'myname' 
     CONNECT BY 
       friendname = PRIOR username 
       AND level <= 3 
     ) 
WHERE username = 'friendname' 
     AND rownum = 1 

actualización del nivel que sea necesario: se puede buscar la tercera capa amigos etc.

Si la relación de amistad es simétrica, se debe hacer la siguiente consulta:

WITH q AS 
     (
     SELECT username, friendname 
     FROM friends 
     UNION ALL 
     SELECT friendname, username 
     FROM friends 
     ), 
     f AS 
     (
     SELECT friendname, level 
     FROM q 
     START WITH 
       username = 'Thomas' 
     CONNECT BY NOCYCLE 
       username = PRIOR friendname 
     ) 
SELECT * 
FROM f 
WHERE friendname = 'Jo' 
     AND rownum = 1 

Esta consulta puede hacerse mucho más rápido si desnormaliza su tabla: almacene dos registros por amistad, como este:

CREATE TABLE dual_friends (orestes NOT NULL, pylades NOT NULL, CONSTRAINT pk_dualfriends_op PRIMARY KEY (orestes, pylades)) ORGANIZATION INDEX 
AS 
SELECT username, friendname 
FROM friends 
UNION ALL 
SELECT friendname, username 
     FROM friends 

a continuación, puedes reemplazar el CTE anterior con el dual_friends:

WITH f AS 
     (
     SELECT pylades, level 
     FROM dual_friends 
     START WITH 
       orestes = 'Thomas' 
     CONNECT BY NOCYCLE 
       orestes = PRIOR pylades 
       AND level <= 3 
     ) 
SELECT * 
FROM f 
WHERE pylades = 'Jo' 
     AND rownum = 1 

, que utilizará el índice y ser mucho más eficiente, sobre todo si se limita el nivel a un valor razonable.

+0

Sin embargo Oracle ha consultas jerárquicas utilizando la conexión por lo que va a hacer el nivel en busca de que – Mark

+0

que SQL parece funcionar para mí. bien, imagínese dada esta tabla nombre de usuario FRIENDNAME Thomas Alice Alice a Bob Bob Jo en ejecución que SQL con myname = Thomas y FRIENDNAME = 'Jo' Jo dar nada indica que no pertenece a la red Thomas, lo cual es incorrecto –

+0

@user: ¿Es ¿Tu relación de amistad es simétrica? Es decir, si 'Alice' es la amiga de' Thomas', ¿es 'Thomas' el amigo de' Alice' también? Creo que lo es, pero es mejor especificarlo. – Quassnoi

Cuestiones relacionadas