【问题标题】:error : #1242 - Subquery returns more than 1 row错误:#1242 - 子查询返回超过 1 行
【发布时间】:2011-12-13 14:44:50
【问题描述】:

我收到一个错误:#1242 - 运行此 sql 时子查询返回多于 1 行。

CREATE VIEW test 
AS 
  SELECT cc_name, 
         COUNT() AS total, 
         (SELECT COUNT(*) 
            FROM bed 
           WHERE respatient_id > 0 
        GROUP BY cc_name) AS occupied_beds, 
         (SELECT COUNT(*) 
            FROM bed 
           WHERE respatient_id IS NULL 
        GROUP BY cc_name) AS free_beds 
    FROM bed 
GROUP BY cc_name; 

【问题讨论】:

  • @Ken White:使用相同的标签/错误消息并不意味着这些是重复的。
  • 第二个是,包括与COUNT相关的问题。四个中的三个解释了错误的含义,这应该导致发布者自己弄清楚。 (就像阅读实际的错误消息一样,查看查询并思考“嗯。两种可能性,因为有两个子查询。也许我应该单独运行它们以查看它们是否返回多行,然后我可以尝试弄清楚那个部分或专门询问它。”
  • @Ken White:标签信息本身解释了行为;)这就是问题的重点,所以有很多示例/示例......
  • :) 明白了。关键是提问者显然完全没有努力自己解决问题。一个简单的搜索就会出现其他 4 个问题,这应该引导他们寻找方向。 SO 是一个很好的资源,但它不应该是解决所有问题的 first 手段。您至少应该先尝试自己解决它,然后看看其他人是否有,然后然后在这里提出一个新问题。我看不到“我试过”或“我搜索过,但其他答案没有帮助,因为”。相反,我看到“我收到一条错误消息。告诉我如何解决它。这是我的代码。” :)

标签: mysql sql mysql-error-1242


【解决方案1】:
SELECT COUNT() 
          FROM   bed 
          WHERE  respatient_id > 0 
          GROUP  BY cc_name

您需要在子查询中删除 group-by,所以可能类似于

SELECT COUNT(*) 
          FROM   bed 
          WHERE  respatient_id > 0 

或者可能 -- 取决于您的应用程序逻辑是什么......

SELECT COUNT(*) from (
          select count(*),cc_name FROM   bed 
          WHERE  respatient_id > 0 
          GROUP  BY cc_name) filterview

【讨论】:

    【解决方案2】:

    问题是您的子选择返回多个值 - IE:

    SELECT ...
           (SELECT COUNT(*) 
              FROM bed 
             WHERE respatient_id IS NULL 
          GROUP BY cc_name) AS free_beds,
           ...
    

    ...将为每个 cc_name 返回一行,但 SQL 不支持压缩子选择的结果集 - 因此会出现错误。

    不需要子选择,这可以通过使用表来完成:

      SELECT b.cc_name, 
             COUNT(*) AS total, 
             SUM(CASE 
                   WHEN b.respatient_id > 0 THEN 1 
                   ELSE 0 
                 END) AS occupied_beds, 
             SUM(CASE 
                   WHEN b.respatient_id IS NULL THEN 1 
                   ELSE 0 
                 END) AS free_beds 
        FROM bed b
    GROUP BY b.cc_name
    

    【讨论】:

    • 我认为你的SUMs 有点老套;正如 a1ex07 所建议的那样,使用COUNTs 更清楚。
    • 抱歉,我很确定你在测试中犯了一个错误。 COUNT 计算所有非NULL 值;在您的附录中,您有一个ELSE 0,这是错误的。 (它必须是ELSE NULL,或者只是省略。)在你的评论中,你省略了ELSE 0,但我敢打赌那不是你实际测试的。
    • @ruakh:感谢您的关注,已更新。但是,当SUM 明确演示如何进行计算时,我看不出它是多么的骇人听闻。显然,COUNT 要求用户注意NULL 处理和适当地构造查询——这使得COUNT 比使用SUM 更“hackish”。
    • 好吧,我猜“hackishness”是主观的,但是当目标是 count 具有特定属性的记录时,我认为使用 @ 有点 hackish/混淆987654336@ 超过 1 和 0 而不是 COUNT 超过 null 和非 null 值。毕竟,COUNT 的全部意义在于计算非空值。但是你的方式显然是有效的,如果你喜欢它,那么我不能给你一个令人信服的客观理由来接受我的偏好而不是你自己的。 :-P 我想我们必须同意不同意。幸运的是,这是一件非常小的事情,可以不同意。 :-)
    • @ruakh:你认为明确说明操作是如何发生的有点骇人听闻?该方法通常被视为“模式”而不是反模式。每个人都有自己的想法,但我想你会发现自己只有自己的信念。如果有性能优势,那么我会支持它,但如果没有,那么我会为外行的维护和可读性而写。
    【解决方案3】:

    您的子查询返回超过 1 行。我认为您需要类似的东西:

     SELECT COUNT(*) AS total, 
     COUNT(CASE WHEN respatient_id > 0 THEN 1 END) AS occupied_beds,
     COUNT(CASE WHEN respatient_id IS NULL THEN 1 END) AS free_beds          
     FROM   bed 
     GROUP  BY cc_name
    

    您也可以尝试使用WITH ROLLUP + pivoting(主要用于学习目的,这是一个更长的查询):

    SELECT cc_name, 
    MAX(CASE 
     WHEN num_1 = 1 THEN tot_num END) AS free_beds,
    
    MAX(CASE 
     WHEN num_1 = 2 THEN tot_num END) AS occupied_beds,
    
    MAX(CASE 
     WHEN num_1 = IS NULL THEN tot_num END) AS total
    
    FROM
    (SELECT cc_name, CASE 
    WHEN respatient_id > 0 THEN 1
    WHEN respatient_id IS NULL THEN 2
    ELSE 3 END as num_1,
    COUNT(*) as tot_num
    FROM  bed
    WHERE 
    CASE 
    WHEN respatient_id > 0 THEN 1
    WHEN respatient_id IS NULL THEN 2
    ELSE 3 END != 3
    GROUP BY cc_name,
    num_1 WITH ROLLUP)A
    GROUP BY cc_name
    

    【讨论】:

      【解决方案4】:

      这是因为您的子查询(括号内的SELECT 位)为每个外行返回多行。问题在于GROUP BY;如果您想为此使用子查询,则需要将它们关联到外部查询,指定它们引用与外部查询相同的cc_name

      CREATE VIEW test 
      AS 
        SELECT cc_name, 
               COUNT()             AS total, 
               (SELECT COUNT() 
                FROM   bed 
                WHERE  cc_name = bed_outer.cc_name
                AND    respatient_id > 0) AS occupied_beds, 
               (SELECT COUNT(*) 
                FROM   bed 
                WHERE  cc_name = bed_outer.cc_name
                WHERE  respatient_id IS NULL) AS free_beds 
        FROM   bed AS bed_outer
        GROUP  BY cc_name;
      

      (有关相关子查询的信息,请参阅http://en.wikipedia.org/wiki/Correlated_subquery。)

      但是,正如 OMG Ponies 和 a1ex07 所说,您实际上不需要为此使用子查询。

      【讨论】:

      • +1:我本来打算演示相关子查询但忘记了。
      • 感谢您的正确回答,我确实需要子查询,而且效果很好
      猜你喜欢
      • 1970-01-01
      • 2013-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      • 1970-01-01
      • 1970-01-01
      • 2016-07-13
      相关资源
      最近更新 更多