SQL Server: how to select First, Second and Third degree contacts

杀马特。学长 韩版系。学妹 提交于 2019-12-01 06:43:16

Here's my approach:

  1. Add my contact to a special collected contact list.

  2. For every contact in the collected list as Contact_1 of the contact table, add its corresponding Contact_2 unless that contact is already in the collected list.

  3. Repeat step #2 the number of times that is the target degree number minus one.

  4. Repeat the query in step #2 once more, but this time simply return the result set (do not add the rows to the collected list).

The script:

DECLARE @MyContact varchar(50), @DegreeNumber int;
SET @MyContact = 'gulsah';
SET @DegreeNumber = 3;

DECLARE @CollectedContacts TABLE (Contact varchar(50));
INSERT INTO @CollectedContacts (Contact) VALUES (@MyContact);

WHILE @DegreeNumber > 1 BEGIN
  INSERT INTO @CollectedContacts (Contact)
  SELECT ct.Contact_2
  FROM Contacts_Table ct
    INNER JOIN @CollectedContacts cc ON ct.Contact_1 = cc.Contact
    LEFT JOIN @CollectedContacts cc2 ON ct.Contact_2 = cc2.Contact
  WHERE cc2.Contact IS NULL;

  SET @DegreeNumber = @DegreeNumber - 1;
END;

SELECT ct.Contact_2
FROM Contacts_Table ct
  INNER JOIN @CollectedContacts cc ON ct.Contact_1 = cc.Contact
  LEFT JOIN @CollectedContacts cc2 ON ct.Contact_2 = cc2.Contact
WHERE cc2.Contact IS NULL;

As you can see, both the degree number and 'my' contact are parametrisable. I'm using the varchar type for contacts, but that of course can easily be replaced with int, if needed.

What makes it difficult is to select contacts of my contacts who are not my first degree contact.

You could use the EXCEPT operator.

First-degree contacts:

SELECT contact_2 FROM contact WHERE contact_1 = 'gulsah'

Second-degree contacts who are not first-degree contacts:

SELECT
  contactB.contact_2
FROM 
  contact AS contactB
  INNER JOIN contact AS contactA ON contactA.contact_2=contactB.contact_1
WHERE contactA.contact_1 = 'gulsah'
EXCEPT
SELECT contact_2 FROM contact WHERE contact_1 = 'gulsah'

EXCEPT tells SQL server to return all the results from the first SELECT that do NOT appear in the second SELECT.

For third-degree contacts (who are not first- or second-degree contacts):

SELECT
  contactC.contact_2
FROM 
  contact AS contactC
  INNER JOIN contact AS contactB ON contactB.contact_2=contactC.contact_1
  INNER JOIN contact AS contactA ON contactA.contact_2=contactB.contact_1
WHERE contactA.contact_1 = 'gulsah'
EXCEPT
(
SELECT contact_2 FROM contact WHERE contact_1 = 'gulsah'
UNION
SELECT
  contactB.contact_2
FROM 
  contact AS contactB
  INNER JOIN contact AS contactA ON contactA.contact_2=contactB.contact_1
WHERE contactA.contact_1 = 'gulsah'
)

I don't hold high hopes for performance, but of course you will need to check this yourself.


As a side note:

I can select mutual contacts but I guess it is not the right approach.

Use INTERSECT for this.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!