【问题标题】:Solution to "subquery returns more than 1 row" error“子查询返回超过 1 行”错误的解决方案
【发布时间】:2015-03-26 03:02:05
【问题描述】:

我有一个返回多行的查询,以及另一个我想将条件设置为来自这些多行的值之一的查询,所以基本上我希望子查询看起来像这样:

select * 
from table
where id= (multiple row query);

multiple row query 返回多行。因此,如果这些行的值为 1、2、3,那么我想将 id 设置为 1 或 2 或 3。

【问题讨论】:

标签: mysql


【解决方案1】:

=可以在子查询只返回1个值时使用。

当子查询返回超过 1 个值时,您将不得不使用IN

select * 
from table
where id IN (multiple row query);

例如:

SELECT *
FROM Students
WHERE Marks = (SELECT MAX(Marks) FROM Students)   --Subquery returns only 1 value

SELECT *
FROM Students
WHERE Marks IN 
      (SELECT Marks 
       FROM Students 
       ORDER BY Marks DESC
       LIMIT 10)                       --Subquery returns 10 values

【讨论】:

  • 对于这个例子,确保你的“多行查询”只返回一列。像 SELECT ID FROM FOO 这样的东西会起作用,而 SELECT ID、NAME FROM FOO 或 SELECT * FROM FOO 不会。
  • @SteveSaporta:你是对的!为了更好地理解,我提供了一些示例。
  • 为什么不在子查询中直接使用 LIMIT 0,1 所以它只给出一个结果?
  • @vividusdesigns:您也可以在示例 1 中使用 limit,只要 子查询只返回一个值。我使用了没有分组依据的 max(),所以子查询肯定只会返回一个值。
  • mariaDB 10.3 它不断抛出错误,如果我使用带有 IF 条件的子查询,这里是 POST ,知道吗?
【解决方案2】:

你可以使用in():

select * 
from table
where id in (multiple row query)

或使用连接:

select distinct t.* 
from source_of_id_table s
join table t on t.id = s.t_id
where <conditions for source_of_id_table>

连接永远不会是性能更差的选择,并且根据具体情况和您使用的数据库,可以提供更好的性能。

【讨论】:

    【解决方案3】:

    在您的 SELECT 查询中使用 MAX 以返回一个值……示例

    INSERT INTO school_year_studentid (student_id,syr_id) VALUES
    ((SELECT MAX(student_id) FROM student), (SELECT MAX(syr_id) FROM school_year))
    

    而不是

    INSERT INTO school_year_studentid (student_id,syr_id) VALUES
    ((SELECT (student_id) FROM student), (SELECT (syr_id) FROM school_year))
    

    尝试不使用 MAX 会返回多个值

    【讨论】:

      【解决方案4】:

      当出现“子查询返回超过 1 行”错误时,数据库实际上是在告诉您存在无法解析的循环引用。这有点像使用电子表格并说单元格 A1 = B1,然后说 B1 = A1。此错误通常与需要具有双重嵌套子查询的场景相关联。我建议您查找一个称为“交叉表查询”的东西,这是解决此问题通常需要的查询类型。它基本上是嵌套在子查询中的外连接(左或右),反之亦然。也可以使用双重连接(也被认为是一种交叉表查询)来解决这个问题,如下所示:

      CREATE DEFINER=`root`@`localhost` PROCEDURE `SP_GET_VEHICLES_IN`(
          IN P_email VARCHAR(150),
          IN P_credentials VARCHAR(150)
      )
      BEGIN
          DECLARE V_user_id INT(11);
          SET V_user_id = (SELECT user_id FROM users WHERE email = P_email AND credentials = P_credentials LIMIT 1);
          SELECT vehicles_in.vehicle_id, vehicles_in.make_id, vehicles_in.model_id, vehicles_in.model_year,
          vehicles_in.registration, vehicles_in.date_taken, make.make_label, model.model_label
          FROM make
          LEFT OUTER JOIN vehicles_in ON vehicles_in.make_id = make.make_id
          LEFT OUTER JOIN model ON model.make_id = make.make_id AND vehicles_in.model_id = model.model_id
          WHERE vehicles_in.user_id = V_user_id;
      END
      

      在上面的代码中注意SELECT子句中有三个表,这三个表出现在FROM子句之后和两个LEFT OUTER JOIN子句之后,这三个表在FROM和LEFT OUTER JOIN之间必须是不同的句法正确。

      值得注意的是,作为开发人员,这是一个非常重要的结构,尤其是在您编写定期报告查询时,它可能是任何复杂交叉引用最重要的技能,因此所有开发人员都应该研究这些结构(交叉表双重连接)。

      我必须警告的另一件事是:如果要将交叉表用作工作系统的一部分而不仅仅是定期报告,则必须检查记录计数并重新配置连接条件,直到最少记录被返回,否则大表和交叉表可能会使您的服务器停止运行。 希望这会有所帮助。

      【讨论】:

        【解决方案5】:

        添加我的答案,因为它阐述了您可以从子查询的表中选择多个列的想法。

        这里我需要最近的演员阵容及其相关信息。

        我首先尝试简单地选择 max(votedate) 以及 vote、itemid、userid 等,但是虽然查询会返回 max votedate,但它也会返回随机行以获取其他信息。在一堆 1 和 0 中很难看到。

        效果很好:

        $query = "  
            SELECT t1.itemid, t1.itemtext, t2.vote, t2.votedate, t2.userid 
            FROM
                (
                SELECT itemid, itemtext FROM oc_item ) t1
            LEFT JOIN 
                (
                SELECT vote, votedate, itemid,userid FROM oc_votes
                WHERE votedate IN 
                (select max(votedate) FROM oc_votes group by itemid)
                AND userid=:userid) t2
            ON (t1.itemid = t2.itemid)
            order by itemid ASC
        ";
        

        WHERE 子句中的子查询 WHERE votedate IN (select max(votedate) FROM oc_votes group by itemid)返回一条记录——投票日期最长的记录。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-13
          • 2023-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多