【问题标题】:SQL select one row from table 1 joining on multiple rows in table 2SQL从表1中选择一行加入表2中的多行
【发布时间】:2014-08-04 17:35:46
【问题描述】:

所以我有两个表,第一个是 users_

Name
------
Carol
Sue

第二个是兴趣_

Name        Interest
----------------------
Carol       Books
Carol       Dancing
Carol       Sports    
Sue         Books
Sue         Dancing

用户将看到复选框,以根据类似兴趣的标准选择匹配项

因此,如果用户选择 Books and Dancing 作为他们比赛的兴趣,我将构建什么类型的 sql 查询来组合多行兴趣并确保结果是 Sue,因为她的兴趣是 Books and Dancing 但不是 Sports ?

任何帮助都会有很大帮助!

【问题讨论】:

  • 感兴趣的地方(“书籍”、“跳舞”...等)。
  • 不清楚你的问题是什么。我了解您希望将用户加入兴趣,但您过滤的是什么以及您想要哪些列?
  • @JohnRuddell 将返回 Carol 和 Sue
  • @JohnRuddell 想想一个约会网站,你想找到对你感兴趣的事物感兴趣的匹配对象,所以结果应该返回符合该条件的人,在这种情况下你'正在寻找一个完全喜欢书和跳舞的人
  • 嗯……这让我想起了一个求职面试问题。

标签: mysql join sql


【解决方案1】:

这是一个简单的方法

select
i.name 
from interests i
where i.interest in ('Books','Dancing')
and not exists
(
  select 1 from interests i1
  where interest not in ('Books','Dancing')
  AND i.name = i1.name
)
group by i.name
having count(*) = 2

DEMO

【讨论】:

  • hmm @JohnRuddell 你说得对,它不需要有子句。
  • 是的,这只会减慢它的速度。按名称分组就足够了 :) 不管 +1 是另一种方法
  • 这个例子有效,当我添加更多具有相同 2 个兴趣的用户时,它返回了所有正确的匹配项,感谢 Abhik!
【解决方案2】:

所以基本上这样做是建立一个超过这两个用户的负面列表,然后选择其他用户

SELECT u.name 
FROM users_ u     
JOIN interests_ i ON i.name = u.name
JOIN
(   SELECT u.name 
    FROM users_ u
    JOIN interests_ i ON i.name = u.name
    WHERE i.interest NOT IN('Books', 'Dancing')
) t
WHERE u.name <> t.name 
  AND i.interest IN('Books', 'Dancing')
GROUP BY u.name
HAVING COUNT(u.name) = 2;

DEMO

【讨论】:

    【解决方案3】:

    实现此结果的一种方法:

    SELECT u.name
      FROM users_ u
      JOIN interests_ n01 ON n01.name = u.name AND n01.interest = 'Books'
      JOIN interests_ n02 ON n02.name = u.name AND n02.interest = 'Dancing'
      LEFT JOIN interests_ x01 ON x01.name = u.name AND x01.interest = 'Sports'
      LEFT JOIN interests_ x02 ON x02.name = u.name AND x01.interest = 'Wine'
     WHERE x01.name IS NULL
       AND x02.name IS NULL
    

    此方法要求“包含”每个兴趣的 JOIN,并“排除”每个兴趣的反连接。这种方法很灵活,但对于大量兴趣而言可能会变得笨拙。

    要仅查找指定兴趣的匹配项,而不必列出所有不匹配的兴趣,我们可以使用反连接来查找兴趣不匹配的行:

    SELECT u.name
      FROM users_ u
      JOIN interests_ n01 ON n01.name = u.name AND n01.interest = 'Books'
      JOIN interests_ n02 ON n02.name = u.name AND n02.interest = 'Dancing'
      LEFT
      JOIN interests_ o 
        ON o.name = u.name
       AND o.interest NOT IN ('Books','Dancing')
     WHERE o.name IS NULL
    

    另一种方法是使用 JOIN 操作和 COUNT() 聚合,例如

    SELECT u.name
      FROM users_ u
      JOIN interests_ n 
        ON n.name = u.name 
       AND n.interest IN ('Books','Dancing')
      LEFT
      JOIN interests_ o
        ON o.name = u.name
       AND o.interest NOT IN ('Books','Dancing')
     WHERE o.name IS NULL
     GROUP BY u.name
    HAVING COUNT(DISTINCT n.interest) = 2
    

    还有其他一些方法(这些只是一些示例)。

    【讨论】:

    • @JohnRuddell:在最后一个查询中,HAVING COUNT 的目的是验证我们“匹配”两个'Books''Dancing',而不是只是其中的一个子集。 (如果我们没有那个,那么查询将返回,例如,在 'Books' 上匹配但在 'Dancing' 上不匹配的用户。)DISTINCT 关键字被抛出,因为我们没有明确给定(name,interest) 将是唯一的约束。
    • 好吧..我只是好奇,因为无论哪种方式它都返回相同的结果。
    • @John Ruddell:考虑扩展示例以包括用户Miranda 有一个兴趣:Dancing。如果没有HAVING COUNT(),查询将返回用户Miranda,因为存在匹配行。如果我们希望所有用户至少匹配一个指定的兴趣,但不一定是所有用户,我们会省略该子句。 (我们需要扩展样本数据来展示差异。)
    • 是的,当你解释的时候我明白了:)
    【解决方案4】:

    使用 SQL in 运算符

    select * from  interests_ where Interest in ('Books', 'Dancing') and Interest not in ('Sports');
    

    编辑 1

    这对我有用

    SELECT * FROM user_ WHERE EXISTS ( 
        SELECT i.Name, count(distinct i.Interest) FROM interests_ as i
        WHERE i.Name=user_.Name
        AND i.Interest IN ('Books','Dancing')
        GROUP BY i.Name
        HAVING count(distinct i.Interest) = 2
    );
    

    参考:SQL equivalent of IN operator that acts as AND instead of OR?

    【讨论】:

    • 这没有考虑到“结果是 Sue,因为她的兴趣是读书和跳舞,而不是运动”
    • @Lamak 我已经编辑了答案,现在解决了吗??
    • 实际上可能有多个匹配项!只是想确保满足条件,所以我可以删除“并且不感兴趣('Sports')”吗?
    • 不,不是,它太具体了。通过您的查询,如果用户只对图书感兴趣,它仍会返回该用户
    • 想象一下,您只需要使用“书籍”和“跳舞”,然后从那里开始......不在“体育”中是个坏主意
    【解决方案5】:

    左连接非常有用。你可以试试这个。

    SELECT users_.*
    FROM users_
        LEFT JOIN interests_
        ON users_.Name = Interests_.Name
                WHERE interests_.Interests = 'Books'
                AND interests_.Interests = 'Dancing'
    

    【讨论】:

    • 这不起作用。你应该考虑为你的表使用别名......更好的 SQL 实践
    • 是的,LEFT JOIN 非常有用。但是这里发布的查询将返回来自users_ 的所有行,并且来自users_ 的一些行将被重复(例如“Sue”和“Carol”。)虽然这可能是一个有趣的结果集,但它不符合要求已指定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-01
    相关资源
    最近更新 更多