【问题标题】:SQL Server: how to select First, Second and Third degree contactsSQL Server:如何选择一级、二级和三级联系人
【发布时间】:2011-04-24 05:51:42
【问题描述】:

我正在处理一个社交网站项目,我需要列出我的联系人的“一级、二级和三级联系人”。我正在使用 SQL Server 和 C#

假设有一个像这样的contact 表:

一级接触:

  • 如果gulsah 是我,那么我的第一学位联系人是burak,sennur

我用来选择这个的查询:

SELECT contact_2 FROM Contacts_Table WHERE contact_1 like 'gulsah'

二级联系人:

如果gulsah 又是我,那么我的二级联系人是:mali

难点在于从我的联系人中选择不是我的一级联系人的联系人。

我可以选择相互联系,但我想这不是正确的方法。

例如,选择我的共同联系人(gulsah)和burak

SELECT contact_1 FROM (SELECT * FROM Contact_Test 
  WHERE contact_2 like 'burak') a
     INNER JOIN (SELECT contact_1 FROM Contact_Test 
     WHERE (contact_2 = 'gulsah')) b 
ON a.contact_1 = b.contact_1

此查询有效,但正如我所说,这不是这项工作的正确方法。

三级联系人:

如果gulsah又是我,那么我的三级联系人是_mehmet,ahmet

我需要从我的联系人的联系人中选择不是我的一级和二级联系人的联系人:)

Here is a post from Linkedin which explains contact level.

感谢您的回复。

【问题讨论】:

  • 您是否考虑过使用 hierarchy functions 或递归 CTE(SO 上的大量示例)来实现这一目标的可能性?不是答案,只是一个想法。
  • 实际上,我在使用左右字段的无限子类别系统中使用层次结构,但老实说,我不明白如何在这个问题上使用这种方法。我想我需要在联系人表上存储一些数据,例如 /1/2/5/ 还是我错了?
  • 与您的问题不严格相关,但我看到两行:{gulsah,burak} 和 {burak,gulsah}。它们代表的不是同一种关系吗?
  • 这两行用于检查 Approval 以供未来开发。例如; burak 可以在 gulsah 的名单中,但同时,gulsah 可能不想被列入 burak 的名单。我刚刚意识到这是一种愚蠢的方法。无论如何,您可以忽略重复的行。

标签: sql sql-server-2008 contacts contact-list


【解决方案1】:

难点在于从我的联系人中选择不是我的一级联系人的联系人。

您可以使用EXCEPT 运算符。

一级联系人:

SELECT contact_2 FROM contact WHERE contact_1 = 'gulsah'

非一级联系人的二级联系人:

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 告诉 SQL Server 返回第一个 SELECT 中没有出现在第二个 SELECT 中的所有结果。

对于三级联系人(不是一级或二级联系人):

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 can select mutual contacts but I guess it is not the right approach.

为此使用INTERSECT

【讨论】:

  • 我会试试这个,我希望低性能不会成为问题。谢谢
【解决方案2】:

这是我的方法:

  1. 将我的联系人添加到专门收集的联系人列表中。

  2. 对于收集列表中的每个联系人作为联系人表的Contact_1,添加其对应的Contact_2,除非该联系人已经在收集列表中。

  3. 重复步骤 #2 目标度数减一的次数。

  4. 再次重复第 2 步中的查询,但这次只返回结果集(不要将行添加到收集的列表中)。

脚本:

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;

如您所见,学位编号和“我的”联系人都是可参数化的。我使用varchar 类型作为联系人,但如果需要,当然可以很容易地用int 替换。

【讨论】:

    【解决方案3】:

    【讨论】:

    • @Snoopy,这篇文章真的很好,岩浆也分享了这个链接。我仔细检查了它,我认为这是适合我情况的完美解决方案之一(社交图数据库除外)。但是在本文中,示例是为 PostgreSQL 编写的,所以我无法在 MSSQL 中运行它。例如,此查询不适用于 sql; "WITH RECURSIVE transitive_closure(a, b, distance, path_string) A..."
    • @Burak:SQL Server 2005 也支持递归公用表表达式。我只是不使用需要 RECURSIVE 关键字的 ANSI 标准语法。如果您省略了 RECURSIVE 关键字,它也应该适用于 SQL Server。
    • @Burak:模型的问题在于,它包含无限循环(例如 gulsah -> burak -> sennur -> gulsah),使用递归公用表表达式无法轻松检测到这些循环......
    • 那你有什么推荐的?我应该遵循哪种方法?这篇文章(图表链接)确实是 Linkedin 工作原理的一个很好的例子,而这正是我所需要的。我需要找到 2 个随机人之间的关系。我应该怎么做,而不是使用递归公用表表达式?图数据库? (neo4j)
    • @a_horse_with_no_name:您对此有何看法:stackoverflow.com/questions/1192945/…(参见 Jose Chama 的评论)
    猜你喜欢
    • 1970-01-01
    • 2014-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多