【问题标题】:SQL Query JOIN or IN operator?SQL 查询 JOIN 或 IN 运算符?
【发布时间】:2015-01-19 13:12:51
【问题描述】:

我有两张桌子, 朋友。 FRIENDS 有 NAME 和 SURNAME 字段。

一个人有 N 个朋友。

我想检索至少有两个 FRIEND 的所有 PERSON,一个名字为“mark”,另一个名字为“rocco”,姓氏为“siffredi”。

示例:如果我有一个人有 5 个朋友,其中一个叫 mark,没有一个叫 rocco siffredi,则不返回任何表格。

我在想:

SELECT * FROM person p
         JOIN friends AS f ON p.ID=f.personID
WHERE f.name ="mark" AND f IN 
            ( SELECT * from FRIENDS WHERE name="rocco" and surname="siffredi")

SELECT * FROM person p
         JOIN friends AS f1 ON p.ID=f1.personID
         JOIN friends AS f2 ON p.ID=f2.personID
WHERE    f1.name="mark" AND f2.name="rocco" AND f2.surname="siffredi"

最好的方法是什么?我的意思是执行它的最快方法。 我不在乎可读性。 还有其他方法可以执行此查询吗? 泰。

编辑:在 ID 上添加了联接...

【问题讨论】:

  • “最好”是什么意思?为了便于阅读,我会使用WHERE EXISTS (...name="mark") AND EXISTS (...name.="rocco" AND surname="siffredi")
  • FK 应该反过来。如果 FK 在Person 表上,那么每个人只能有一个朋友。
  • 编辑了 FK。编辑了预期的“最佳”

标签: sql sql-server logical-operators


【解决方案1】:

我不得不猜测你的列名并组成一个表格:

使用 EXISTS:

CREATE table FRIENDS(person_id INT, friend_id INT)

go

SELECT * 
FROM person 
WHERE 
  EXISTS
   (SELECT * 
    FROM friends f 
    JOIN person per
    ON f.friend_id = per.id
    WHERE
      per.name ='mark' AND
      person.id = f.person_id) AND
  EXISTS
   (SELECT * 
    FROM friends f 
    JOIN person per
    ON f.friend_id = per.id
    WHERE
      per.name = 'rocco' AND
      per.surname='siffredi' AND
      person.id = f.person_id)

【讨论】:

  • 你的第二个存在永远不会返回任何东西,因为 per.name 不能同时是 Mark 和 Rocco。
  • @Spock 很好看,我复制粘贴太多了,已经更正了
  • 与我提出的第二个查询有何不同?
  • @Gaetano 您缺少对 person 表的引用。让你无法参考朋友的名字
  • 我不能在JOINs上引用有AS的朋友的名字?
【解决方案2】:

您的架构设计对于您正在尝试做的事情不是很好...我会像您一样拥有一个 Person 表,其中还包含一个名为 PersonId 的唯一标识符。然后我会有一个 Friends 表,它包含两个字段 - Person1Id 和 Person2Id。

这为您提供了几个重要的优势 - 首先,您的系统能够处理多个名为 John Smith 的家伙(因为我们加入的是 Ids 而不是 Names...)。其次,一个人的详细信息只记录在 Person 表中。真理的一种定义...

【讨论】:

  • 我在想,ID 显然在那里。让我编辑答案。
【解决方案3】:

以这些数据作为输入:

INSERT INTO Person VALUES 
(1, 'Bob', 'Smith'),
(2, 'Jim', 'Jones')

INSERT INTO Friends VALUES
(1, 1, 'Mark', 'Tally'),
(2, 1, 'John', 'Smith'),
(3, 1, 'Jack', 'Pollock'),
(4, 2, 'Mark', 'Rush'),
(5, 2, 'Rocco', 'Siffredi'),
(6, 2, 'Mark', 'Bush')

你可以使用这个查询:

SELECT PersonId, COUNT(*) AS NoOfFriends
FROM (
   SELECT DISTINCT PersonId, Name,
          Surname = CASE WHEN NAME = 'Mark' THEN NULl
                         ELSE Surname
                    END  
   FROM Friends
   WHERE Name = 'Mark' OR (Name = 'Rocco' AND Surname = 'Siffredi') ) t
GROUP BY PersonId

获取每个PersonID所需的不同数量的朋友:

PersonId    NoOfFriends
------------------------
1           1
2           2

您现在可以在PersonId 上加入上表表达式并通过NoOfFriends 对其进行过滤:

SELECT p.*
FROM Person AS p
INNER JOIN (
   SELECT PersonId, COUNT(*) AS NoOfFriends
   FROM (
      SELECT DISTINCT PersonId, Name,
             Surname = CASE WHEN NAME = 'Mark' THEN NULl
                         ELSE Surname
                       END  
      FROM Friends
      WHERE Name = 'Mark' OR (Name = 'Rocco' AND Surname = 'Siffredi') ) t
   GROUP BY PersonId ) s ON s.PersonId = p.ID 
WHERE s.NoOfFriends = 2

以便只获得具有所需关联朋友组合的人:

ID  Name    Surname
-------------------
2   Jim     Jones

附:在@t-clausen.dk 发表评论后,我已经完全重写了我的答案。

【讨论】:

  • 如果这个人有 2 个朋友叫 mark 会失败
  • @t-clausen.dk 如果您愿意,可以看看我的新答案。它认为它现在可以正常工作,但我不确定它是否比您的解决方案更有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-06
  • 2016-04-09
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 2011-09-21
  • 1970-01-01
相关资源
最近更新 更多