【问题标题】:Mysql query - Operand should contain 1 columnMysql 查询 - 操作数应包含 1 列
【发布时间】:2026-01-03 11:40:01
【问题描述】:

我在这里讨论了几个话题,但我无法让它发挥作用。对于每个“底池”,我想获得与该底池相关的付款次数以及全部佣金(所有付款佣金的总和)。

SELECT id, id_user,
       ( SELECT IFNULL( SUM(amount), 0 ) AS collectedA, 
                IFNULL( SUM(commission), 0 ) AS commission 
                FROM payment AS pay WHERE pay.id_pot = pot.id AND pay.stat = 1 ) FROM pot

上面给了我标题中提到的错误。我知道我们不能用这种子查询选择两列。 我试图通过 LEFT OUTER JOIN 但无法让它工作。

SELECT id, id_user, 
       IFNULL( SUM(payment.amount), 0 ) AS collectedA, 
       IFNULL( SUM(payment.commission), 0 ) AS commission
FROM pot LEFT OUTER JOIN payment ON payment.id_pot = pot.id AND payment.stat = 1

但这给了我奇怪的结果......

【问题讨论】:

    标签: mysql sql subquery left-join


    【解决方案1】:

    你必须 LEFT JOIN 到一个已经聚合的派生表,像这样:

    SELECT id, id_user, collectedA, commission 
    FROM pot 
    LEFT JOIN (
       SELECT id_pot,
              IFNULL( SUM(amount), 0 ) AS collectedA, 
              IFNULL( SUM(commission), 0 ) AS commission 
       FROM payment  
       WHERE stat = 1 
       GROUP BY id_pot
    ) AS pay pay.id_pot = pot.id
    

    在子查询中执行的GROUP BY 保证您将pot.id 获得一条记录

    【讨论】:

    • 谢谢乔治。这将选择所有的罐子。如果我有一个 where 子句只选择其中的一部分,我应该把它放在哪里以使其高效?在两个子查询上?如果我只需要几个,我想阻止它计算每个底池的总和......任何帮助表示赞赏。
    • 好的。说得通。非常感谢。
    【解决方案2】:

    您的LEFT JOIN 是正确的,但您忘记使用GROUP BY

    SELECT pot.id, id_user, 
           IFNULL( SUM(payment.amount), 0 ) AS collectedA, 
           IFNULL( SUM(payment.commission), 0 ) AS commission
    FROM pot 
    LEFT OUTER JOIN payment ON payment.id_pot = pot.id AND payment.stat = 1
    GROUP BY pot.id
    

    如果您需要WHERE 子句来仅选择部分罐,请将其放在LEFT OUTER JOIN 之后。

    SELECT pot.id, id_user, 
           IFNULL( SUM(payment.amount), 0 ) AS collectedA, 
           IFNULL( SUM(payment.commission), 0 ) AS commission
    FROM pot 
    LEFT OUTER JOIN payment ON payment.id_pot = pot.id AND payment.stat = 1
    WHERE ...
    GROUP BY pot.id
    

    【讨论】:

    • 谢谢巴马尔。与 Giorgos 的解决方案相比,这有多好?我不得不说我有点担心只为列表的一小部分计算太多。
    • 当您有WHERE 子句时,这应该避免计算不相关付款的总和。
    【解决方案3】:

    最有效的方法可能是两个子查询,特别是如果您想在pot 表上设置过滤器:

    select pot.id, pot.id_user,
           (select sum(pay.amount)
            from payment pay
            where pay.id_pot = pot.id and pay.stat = 1
           ) as amount,
           (select sum(pay.commission)
            from payment pay
            where pay.id_pot = pot.id and pay.stat = 1
           ) as commission
    from pot;
    

    为了有效地工作,您需要在payment(id_pot, stat, amount, commission) 上建立索引。这是两个查询的覆盖索引(意味着所有列都在索引中。

    这似乎有点违反直觉,但它不需要全局聚合——所有聚合都可以使用索引扫描来处理。这通常更快。此外,pot 上的任何其他过滤器都会减少 payment 表上的工作需求。

    【讨论】: