【问题标题】:Subquery returns more than 1 row in SELECT part(Dlookup to MySql)子查询在 SELECT 部分返回超过 1 行(Dlookup 到 MySql)
【发布时间】:2020-02-12 09:33:52
【问题描述】:

我正在将桌面应用程序从 MS Access VBA 迁移到 Java Springboot 应用程序,我需要在 MySQL 中进行 VBA 查询。 VBA 查询非常大,所以我向您展示一个较小的示例来演示我的情况。 VBA 查询:

SELECT SELECT tbl_trade.id, 
   DLookUp("[price]","tbl_so_manifest","[so_id] = " 
   & tbl_trade.so_id & " AND [product_id] = " & tbl_po_manifest.product_id),
   // .... many more attributes....
FROM tbl_so_manifest as sm (((
   /// 15 nested INNER JOINS ....
   INNER JOIN tbl_trade AS t ON sm.so_id = t.so_id 
   INNER JOIN tbl_po_manifest AS pm ON sm.product_id = pm.product_id
   )));

MySQL 转换:

SELECT SELECT tbl_trade.id, 
   (SELECT sm.product_id 
   FROM tbl_so_manifest as sm 
      INNER JOIN tbl_trade AS t ON sm.so_id = t.so_id 
      INNER JOIN tbl_po_manifest AS pm ON sm.product_id = pm.product_id), 
   // ......
FROM tbl_so_manifest as sm (((
   /// 15 nested INNER JOINS ....
   INNER JOIN tbl_trade AS t ON sm.so_id = t.so_id 
   INNER JOIN tbl_po_manifest AS pm ON sm.product_id = pm.product_id
   )));

但它给出了错误

错误代码:1242。子查询返回超过 1 行 0.844 秒

需要有关如何处理此问题的建议。

【问题讨论】:

  • 在一个非常高的级别 - 直接的解决方案是让您的每个子查询使用 LIMIT 子句 w3schools.com/sql/sql_top.asp 。 Dlookup 返回匹配条件的第一次出现,因此您只需通过获取子查询中返回的第一个值来模拟相同的行为。
  • tbl_so_mainfest 中每个唯一的 so_idproduct_id 是否有多个价格? MySQL 子查询也不会像 MS Access' DLookUp 那样检索 price 以及为什么 INNER JOIN
  • @Parfait。 tbl_so_mainfest 中没有每个唯一的 so_id 和 product_id 只有一个价格。我使用了内部连接,因为我不确定还有什么。请有任何建议。
  • @Mike。很好的观察,Dlookup 只返回一行。谢谢

标签: mysql sql vba ms-access


【解决方案1】:

您可以强制子查询只返回一个前 1 的记录

所以这个:

DLookUp("[price]","tbl_so_manifest","[so_id] = " 
& tbl_trade.so_id & " AND [product_id] = " & tbl_po_manifest.product_id)

变成:

(SELECT TOP 1 Price FROM tbl_so_manifest 
         WHERE so_ID = tbl_trade.so_id AND product_id = sm.product_id
         ORDER BY PRICE, ID DESC) AS MyPrice

因此,您实际上不需要加入,只需“提取”值即可。将子查询限制为ONE记录,TOP 1和“PK”的顺序将确保只返回一行。如果你省略了“id”,那么如果两个最高价格相同,那么你会得到两行。通过在 order by 中添加“ID”,即使 5 个价格相同,您也只会得到一行。

如果上下文中的其他表具有相同的列名,那么当然要在上面添加表限定符(但是,它是按速记来写的)。

因此,作为一般规则,您可以将 dlookup() 替换为上述类型的查询。 我对 MySQL 不是很熟悉,所以你可能无法使用上面的表别名,但总而言之,使用前 1 并使用“ID(或 PK)在价格或其他情况下折腾其中可能存在多于一行。在大多数情况下,dlookup() 不应有多个值(但 dlookup() 始终只返回一个值)。因此,在大多数从 dlookup() 到子查询的“翻译”中, top 1 应该不是必需的。

而且我不认为 dlookup() 需要“加入”。 Dlookup() 总是命中一个表,从 dlookup() 到子查询的转换也是如此。您希望提取列、表格,然后是条件)。

如果 dlookup() 是 FK 值,则查找表的左连接更容易,不会导致查询中出现额外的行,但任何一种方法都可以。我发现子查询与返回的主查询行数“混淆”的可能性较小。

因此,dlookup() 到子查询是一对一的转换。不需要加入,正如在大多数情况下所指出的那样,在大多数情况下不需要附加的 TOP one + 附加的“id/pk”。

【讨论】:

  • 我理解你的观点,我需要选择第一行,但你建议如果我使用 "Select price FROM tbl_so_manifest as sm WHERE sm.so_id = tbl_trade.so_id AND sm,我不需要使用联接.product_id = tbl_po_manifest.product_id 按价格订购,ID 限制 1;"然后它在“where 子句”中显示未知列 tbl_trade.so_id。这个错误是我使用 INNER JOIN 的原因
  • 您需要连接表还是仅在该查找中? dlookup() 是到子查询的一对一转换。您原始帖子中的其他列稍后会通过连接出现。如果仅在 dlookup() 和现在的子查询中需要连接值,那么很好。您作为书面形式的原始查询连接在更远的附加列中。如果将连接放在子查询中,那么稍后发生的连接呢? (你会做两次)。并且在 join 上倾倒后者意味着您正在极大地改变查询的含义。
  • 我只是建议您采用逻辑上的一对一转换。这样,您无需完全更改或了解原始逻辑即可修改查询。子查询可能无法使用或从您稍后拥有的连接中获取列,但我至少会尝试采用从 dlookup() 到子查询的一对一逻辑翻转。如果您有多个 dlookups() ,那么您必须一遍又一遍地重复连接,而不是最后在主查询中进行一次连接。对MySQL不熟悉,不知道后面的加入列能不能用。
【解决方案2】:

考虑删除子查询的INNER JOINs,因为您没有在 MS Access'DLookUp 中执行此操作(有趣的是,您没有在其条件逻辑中使用指定的别名)。请记住SELECT(具有讽刺意味的是第一个列出的子句)通常是 SQL 操作顺序中的最后一个,因此它可以在子查询中读取外部列 t.so_idpm.product_id

...
  (SELECT sm.`price`
   FROM tbl_so_manifest as sm 
   WHERE sm.so_id = t.so_id 
     AND sm.product_id = pm.product_id) AS sub_name 
...

更有效地使用子查询作为派生表(或 MySQL 8 中的 CTE)与所有其他表连接。这避免了逐行计算并运行一次查找以加入完整的结果集。

SELECT 
   sm.`price`,
   ...
FROM tbl_so_manifest as sm
/// 15 nested INNER JOINS ....
INNER JOIN tbl_trade AS t ON sm.so_id = t.so_id 
INNER JOIN tbl_po_manifest AS pm ON sm.product_id = pm.product_id
INNER JOIN (
    SELECT `so_id`, `product_id`, `price`
    FROM tbl_so_manifest
   ) sm
 ON sm.so_id = t.so_id 
 AND sm.product_id = pm.product_id;

注意:MySQL 不需要在多个 JOINs 周围加上括号(希望我的 MS suggestion 有一天会在 MS Access SQL 中修复)。

【讨论】:

    【解决方案3】:

    您可以使用 LIMIT 1 个关键字将子查询限制为仅返回一个记录。 (从 tbl_so_manifest 中选择价格 在哪里 so_ID = tbl_trade.so_id AND product_id = sm.product_id ORDER BY PRICE, ID DESC LIMIT 1) AS MyPrice

    【讨论】:

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