【问题标题】:Selecting with subqueries in MySQL (Subqueries with ANY, and IN)在 MySQL 中使用子查询进行选择(带有 ANY 和 IN 的子查询)
【发布时间】:2010-10-11 08:55:32
【问题描述】:

感谢您的精彩回答!

更多信息


这很难解释,所以让我们开始吧......

userActions         userGroupMap
+------+--------+   +------+-------+
| user | action |   | user | group |
+------+--------+   +------+-------+
| x    | acted! |   | x    | a     |
| y    | acted! |   | y    | a     |
| y    | acted! |   | z    | b     |
| z    | acted! |   +------+-------+
| y    | acted! |
| z    | acted! |
| x    | acted! |
| z    | acted! |
+------+--------+

我想选择组 a 的操作。我的想法是

SELECT actions, user FROM userActions
    WHERE user = (SELECT user, group FROM userGroupMap WHERE group = a)

但显然这个子查询返回不止一行。我应该使用 JOIN 吗?

Subquery returns more than 1 row

【问题讨论】:

    标签: mysql mysql-error-1242


    【解决方案1】:

    一种方法是这样的:

    SELECT actions,
           user
    FROM   userActions
    WHERE  user IN
                   (SELECT user
                   FROM    userGroupMap
                   WHERE   [group] = 'a'
                   );
    

    但是,对于大型表,此查询往往效率低下,最好进行连接:

    SELECT actions,
           userActions.user
    FROM   userActions
           INNER JOIN
                  (SELECT user
                  FROM    userGroupMap
                  WHERE   [group] = 'a'
                  ) AS tmp
           ON     userActions.user = tmp.user;
    

    或者,正如 Jonathon 所提到的,您可以这样做,而且效率几乎相同,甚至更多:

    SELECT actions,
           userActions.user
    FROM   userActions
           INNER JOIN userGroupMap
           ON     userActions.user = userGroupMap.user
    WHERE  [group] = 'a';
    

    【讨论】:

    • 谢谢!有了你的回答,我的结果完美无缺。我也很欣赏关于大桌子的说明(这就是我接受你的回答的原因)。您能否详细说明为什么将 group 放在括号中-“[group]”?
    • 没有明显的理由需要子查询;带有过滤 WHERE 子句的直接内连接也应该可以完成这项工作。
    • @Blaine:我将 [group] 放在括号中是因为它是一个关键字,如果没有明确说明用作列/表名称的关键字,一些 DBMS 会崩溃。同样的原因,我将 [table] 放在括号中。 @Jonathan Leffler:你说得对,我想我只是被这个问题分心了,它使用了子查询。
    • 再次感谢,这是一个非常有帮助的答案!
    【解决方案2】:
    SELECT actions, user FROM userActions
        WHERE user IN (SELECT user FROM userGroupMap WHERE group = a)
    
    SELECT actions, user FROM userActions
        WHERE user = ANY (SELECT user FROM userGroupMap WHERE group = a)
    

    (修改:如其他人所述,仅应返回用户列。)

    【讨论】:

      【解决方案3】:

      实际上,这个查询会给你你所需要的:

      SELECT actions, user 
      FROM userActions 
      WHERE user IN 
          (SELECT user FROM userGroupMap WHERE group = 'a')
      

      【讨论】:

        【解决方案4】:

        你就不能这样做:

        SELECT 
          a.actions, 
          a.user 
        FROM 
          userActions a 
          INNER JOIN userGroupMap g 
            ON a.user = g.user
        WHERE
          g.group = 'a'
        

        【讨论】:

        • 是的;这在这种情况下效果最好。但也存在“如何处理返回多行的子查询”的问题,这是通过 IN 或 = ANY 或其变体完成的。但是这些查询通常可以用连接而不是子查询来重写。
        【解决方案5】:

        使用联接而不是子查询:

        SELECT
            userActions.action,
            userActions.user
        FROM
            userActions
        CROSS JOIN userGroupMap ON 
            userGroupMap.user = userActions.user AND
            userGroupMap.group = 'a'
        

        【讨论】:

        • 在大表上,这将在与组一起削减之前显着增加临时表的大小。它的效率低于加入数据子集。
        • 如果把 where 语句放在 join 中怎么办?会更好吗?
        • 不需要交叉连接;使用 INNER JOIN(或只是简单的 JOIN)。
        • 在 MySQL 中,CROSS JOIN 是一种等同于 INNER JOIN 的语法(它们可以相互替换)。在标准 SQL 中,它们是不等价的。 INNER JOIN 与 ON 子句一起使用,否则使用 CROSS JOIN。
        【解决方案6】:
        SELECT actions, user FROM userActions
            WHERE user = (SELECT user FROM userGroupMap WHERE group = a)
        

        子查询应该只返回用户,却返回了用户和组(两个​​字段)。

        【讨论】:

        • 我同意子查询错误的部分原因是多列;但是,问题是它返回不止一行,而您的版本仍然这样做 - 因此在运行时失败。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-27
        • 1970-01-01
        • 2020-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-28
        相关资源
        最近更新 更多