I have this problem. Given a users
table that consists of users' username in a social network and friends
table that contain a user's name and a user's friendname like below...
username friendname
John Thomas
Chris James
... I'm trying to write an SQL statement that will if a user is in my network. In other words is that user a friend or friend of friends?
I've been dancing around this problem and could only come up with this query:
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';
It basically check if a user if is a friend of my friend i.e. just return null if false.
Trying to figure out how I can expand to go through all my network of friend. I mean not just friend of my friend.
To process most native dynamic SQL statements, you use the EXECUTE IMMEDIATE statement. To process a multi-row query ( SELECT statement), you use OPEN-FOR , FETCH , and CLOSE statements. Note: To use native dynamic SQL, the COMPATIBLE initialization parameter must be set to 8.1.
Description Oracle Database offers the ability, in both SQL and PL/SQL, to specify our own user-defined delimiters for string literals. Here's how it works: you prefix your literal with the letter "q". Then you type a single quote, followeed by your starting delimiter for the literal.
Instead of coding the query twice, with different ORDER BY clauses, you can construct the query dynamically to include a specified ORDER BY clause. Dynamic SQL programs can handle changes in data definitions, without the need to recompile. This makes dynamic SQL much more flexible than static SQL.
Bind variables are «substituion» variables that are used in place of literals (such as 674, 234, 332) and that have the effect of sending exactly the same SQL to Oracle every time the query is executed. For example, in our application, we would just submit.
SELECT *
FROM (
SELECT username
FROM friends
START WITH
username = 'myname'
CONNECT BY
friendname = PRIOR username
AND level <= 3
)
WHERE username = 'friendname'
AND rownum = 1
Update the level as necessary: you may search for the third layer friends etc.
If the friendship relationship is symmetric, you should make the following query:
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
This query can be made much faster if you denormalize your table: store two records per friendship, like this:
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
Then you can just replace the CTE
above with the 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
, which will use the index and be much more efficient, especially if you limit the level to some reasonable value.
You can use connect by
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With