3

I have a table to keep friend information, with columns MemberID and FriendID. Here is some sample data:

RecordID MemberID FriendID
-------- -------- --------
   1        10       12    
   2        12       10    
   3        10       14    
   4        15       10    
   5        14       12    
   6        10       13    
   7        11       13

I need to find the friends of any Member, either in the MemberID column or the FriendID column.

For example:

  • The friends for MemberID 10 are 12, 13, 14, 15.
  • The friends for MemberID 14 are 10, 12.

I have tried many ways to get the values with a query, but all in vain.

Please suggest the best SQL query to accomplish the task in a single statement.

4

2 回答 2

4

您是否尝试过使用工会进行查询?

SELECT FriendID
FROM mytable
WHERE MemberID = {The ID}
UNION
SELECT MemberID AS FriendID
FROM mytable
WHERE FriendID = {The ID}

如果您需要它与众不同并且可能有重叠,您还可以使用:

SELECT DISTINCT FriendID
FROM (
    SELECT FriendID
    FROM mytable
    WHERE MemberID = {The ID}
    UNION
    SELECT MemberID AS FriendID
    FROM mytable
    WHERE FriendID = {The ID}
) Derived

为了非常清楚,请务必替换{The ID}为您要查找的任何 ID。

于 2013-02-27T06:38:27.760 回答
3

这将进行一次扫描。无需执行 -- 这UNION将需要 2 次扫描并且性能更差。

SELECT DISTINCT
   M.FriendID
FROM
   dbo.Friend F
   CROSS APPLY (VALUES
      (F.MemberID, F.FriendID),
      (F.FriendID, F.MemberID)
   ) M
WHERE
   M.MemberID = 10;

看到这个在 Sql Fiddle 中工作

现在要自相矛盾了——我想了更多。仅当您没有索引时,我关于扫描的陈述才是正确的。MemberID但是,如果你在两个和上都有一个单独的索引FriendID(一个是聚集的,另一个是非聚集的),那么一个UNION方法实际上会执行得更好,因为它会执行两次查找而不是扫描。因此,因此,我实际上建议您坚持UNION并让这些索引继续运行。

SELECT FriendID FROM dbo.Friend WHERE MemberID = 10
UNION
SELECT MemberID FROM dbo.Friend WHERE FriendID = 10;

此外,我建议无论您选择哪种查询,RecordID都应从表中删除该列Friend。此列完全没有必要,因为任何时候您想引用朋友之间的关系,您都可以简单地使用 的组合键(MemberID, FriendID)。通过删除此列,每行将占用更少的字节,这将获得每页更多的行,这将导致获得相同数据的读取次数减少——这是一个提高性能的胜利。如果表中没有其他列,则通过删除RecordID!

以下是实施这些建议的方法:

-- if RecordID is part of the PK
ALTER TABLE dbo.Friend DROP CONSTRAINT PK_Whatever;

-- if RecordID is part of a separate non-PK clustered index
DROP INDEX dbo.Friend.CI_Whatever;

-- If the PK is not already over these two columns
ALTER TABLE dbo.Friend
   ADD CONSTRAINT PK_Friend PRIMARY KEY CLUSTERED (MemberID, FriendID);

CREATE NONCLUSTERED INDEX IX_Friend_FriendID_MemberID
   ON dbo.Friend (FriendID) -- MemberID is implicitly included.

请注意,最终的非聚集索引现在是上述UNION查询第二部分的“覆盖”索引,这意味着它不需要命中聚集索引来满足查询的该部分。所以你现在得到 2 次搜索,性能最好。

于 2013-02-27T06:46:10.800 回答