【问题标题】:How can I select mysql data with a union statement where the data matches each select statement, i.e. combine the AND operator with UNION?如何使用数据与每个选择语句匹配的联合语句选择 mysql 数据,即将 AND 运算符与 UNION 结合使用?
【发布时间】:2012-01-21 10:38:05
【问题描述】:

假设我有一个只有两列的表:name 和 mood。一行包含一个人的姓名和他们的心情,如果他们有多种心情,则在数据库中存储多行。

例如,数据库中有约翰,他快乐、兴奋、自豪。

这表示为

John Happy
John Excited
John Proud

我想做的是根据遇到的几种情绪来选择名称。类似于 UNION:

SELECT name WHERE mood=Happy
UNION
SELECT name WHERE mood=Excited
UNION
SELECT name WHERE mood=Proud

但是使用上述联合会导致:

John
John
John

Union all 将产生 John 的一个结果,但它也会选择仅匹配其中一个查询的任何名称。

我可以想出一些算法来获取每个单独的 mysql_result 资源(我正在使用 PHP),并寻找匹配的结果,但我想知道 MySQL 是否已经促进了这一点。

我意识到上面是一个相当模糊的概括,不用说我的实际程序要复杂得多,我已经为这个问题把它简化了一点,请不要犹豫提问。

【问题讨论】:

    标签: php mysql select union advanced-search


    【解决方案1】:

    如果您没有重复项,您可以使用子查询来完成:

    SELECT `name` FROM (
        SELECT `name`, COUNT(*) AS `count` FROM `moods`
        WHERE `mood` IN ('Excited', 'Happy', 'Proud') GROUP BY `name`
    ) WHERE `count` = 3
    

    或者,您可以使用连接:

    SELECT `m1`.`name` FROM `moods` `m1`
    JOIN `moods` `m2` USING (`name`)
    JOIN `moods` `m3` USING (`name`)
    WHERE `m1`.`mood` = 'Excited' AND `m2`.`mood` = 'Happy' AND `m3`.`mood` = 'Proud'
    

    不那么可爱,但如果你使用 LIMIT 可能会更快。或者可能不是。很大程度上取决于查询规划器。

    UPD:感谢 Tudor Constantin 提醒我有关 HAVING,第一个查询可以是:

    SELECT `name` FROM `moods`
    WHERE `mood` IN ('Excited', 'Happy', 'Proud')
    GROUP BY `name`
    HAVING COUNT(*)>3
    

    【讨论】:

    • 谢谢,我使用了第一个,它工作得非常完美,我有一个 CRON 工作每晚检查重复项,所以不用担心。至于更新,它不返回任何结果,应该有什么区别?非常感谢。
    • 逻辑和HAVING差不多,不知道有没有性能差异。
    【解决方案2】:

    将 UNION 替换为 INTERSECT 。

    【讨论】:

    • MySQL 中没有INTERSECT
    • 这会起作用(在带有INTERSECT 的 SQL 中),但本质上使用 3 个选择来实现 可以 使用一个选择来完成什么似乎效率低下?
    【解决方案3】:

    您的查询已经正确。您可以在WHERE 子句中使用您搜索的单词来ADD 一个额外的列。

    SELECT name,'Happy' as imood WHERE mood='Happy'
      UNION
    SELECT name,'Excited' as imood WHERE mood='Excited'
      UNION
    SELECT name,'Proud' as imood WHERE mood='Proud'
    

    【讨论】:

    • 非常感谢您的回答,非常感谢。问题是这会返回仅满足其中一个选择语句而不是全部的人的姓名。
    【解决方案4】:

    如果我正确理解您的问题,我认为在这种情况下您实际上不需要 UNION,而只需要 WHERE 语句中的多个条件。

    试试这个:

    SELECT name, mood FROM myTable WHERE mood in ('Happy','Excited','Proud')
    

    这应该给出结果:

    John, Happy
    John, Excited
    John, Proud
    

    如果您不在乎获得多个情绪结果,请尝试以下操作:

    SELECT DISTINCT name FROM myTable WHERE mood in ('Happy','Excited','Proud')
    

    哪个会给出:

    这应该给出结果:

    John
    

    更新 如果要匹配所有条件,则可能必须使用子选择:

    SELECT DISTINCT name FROM myTable 
    WHERE name IN 
        (SELECT name FROM myTable WHERE mood = 'Happy')
    AND name IN
        (SELECT name FROM myTable WHERE mood = 'Excited')
    AND name IN
        (SELECT name FROM myTable WHERE mood = 'Proud')
    

    【讨论】:

    • 保罗,感谢您的回复,非常感谢。使用 SELECT DISTINCT 似乎没有带来任何结果,而您的第一个解决方案确实带来了所有结果。
    • 这不是返回至少一种情绪匹配的所有名称(不是全部三种)吗?
    • 刚刚再试一次,实际使用 DISTINCT 会带来结果,但它们并不匹配每个条件,即返回其他只是高兴的人。 AND 运算符能否以某种方式应用于您的解决方案?
    【解决方案5】:

    尝试:

    SELECT name FROM user_moods um1 
      INNER JOIN user_moods um2 ON um1.name = um2.name
    WHERE um1.mood IN ('Happy','Excited','Proud')
    GROUP BY um2.mood
    HAVING COUNT(um2.mood) = 3 # the number of different moods
    

    【讨论】:

    • 好一个,我忘了 HAVING,但是为什么要额外加入呢?此外,MySQL 手册指出“例如,HAVING 子句必须在任何 GROUP BY 子句之后和任何 ORDER BY 子句之前。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多