【问题标题】:Can't get head round mysql subquery无法绕过mysql子查询
【发布时间】:2011-03-30 12:45:58
【问题描述】:

我无法在 Mysql 中处理子查询。相当简单的也可以,而且我发现的大多数教程很少超出典型:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

我试图从我的数据库中提取的内容如下(我会尽力解释这一点,而无需任何数据库背景):

在另一列中检索属于特定代表的客户列表和上个月花费的总金额(在一个列中)和本月迄今花费的金额。

结果大致如下:

ID | NAME   | PREV MONTH | CUR MONTH
1  | foobar | £2300      | £1200
2  | barfoo | £1240      | £500

我用来获取第一部分数据的查询如下:

SELECT c.id,c.name, SUM(co.invoicetotal) as total
FROM customers as c
JOIN customerorders as co on co.customer_id = c.id
WHERE c.salesrep_id = 24
AND co.orderdate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()
GROUP by c.id
order by total desc

DATE_SUB 可以替换为实际日期,因为 php 变量最终会出现在这里。作为一个例子,这只是给了我有效的数据。

这给了我,例如:

ID | NAME   | TOTAL 
1  | foobar | £2300      
2  | barfoo | £1240   

因此,理想情况下,我的子查询将是完全相同的查询,但日期已更改。我不断收到#1242 - Subquery returns more than 1 row 错误。

请问有什么建议或意见吗?

提前致谢。 抢

【问题讨论】:

    标签: sql mysql subquery mysql-error-1242


    【解决方案1】:

    您收到错误的原因是:

    WHERE column1 = (SELECT column1 FROM t2)
    

    t2.column1 正在返回多个结果,但由于子查询之前的等号运算符 - 只能接受 一个 值.

    所以您要么需要将其更改为 IN:

    WHERE column1 IN (SELECT column1 FROM t2)
    

    ...接受多个值。或者将子查询更改为仅返回一个变量 - 此示例返回整个表的最高 t2.column1 值:

    WHERE column1 = (SELECT MAX(column1) FROM t2)
    

    这完全取决于您要获取的数据。

    【讨论】:

      【解决方案2】:
      SELECT  c.id, c.name,
              (
              SELECT  SUM(co.invoicetotal)
              FROM    customerorders co
              WHERE   co.customer_id = c.id
                      AND co.orderdate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()
              ) AS prev_month,
              (
              SELECT  SUM(co.invoicetotal)
              FROM    customerorders co
              WHERE   co.customer_id = c.id
                      AND co.orderdate BETWEEN CURDATE() AND CURDATE() + INTERVAL 1 MONTHS
              ) AS cur_month,
      FROM    customers as c
      WHERE   c.salesrep_id = 24
      ORDER BY
              prev_month DESC
      

      【讨论】:

      • 这很有效,非常感谢。也感谢其他所有人的贡献。尽管我很可能会使用 Quassnoi 的查询来满足我的目的,但我仍然会仔细阅读您的所有答案来帮助我学习,干杯。
      【解决方案3】:

      OMG Ponies 对您出现该错误的原因是正确的。用于比较的子查询必须始终返回单个值。

      我的猜测是您需要创建两个子查询(一个用于 prev,一个用于 curr)并通过用户 ID 加入它们。像这样的:

      SELECT prev.id,prev.name, prev.total, curr.total
      FROM
      (
      SELECT c.id,c.name, SUM(co.invoicetotal) as total  
      FROM customers as c JOIN customerorders as co on co.customer_id = c.id  
      WHERE c.salesrep_id = 24  
      AND co.orderdate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()  
      GROUP by c.id ORDER BY total desc  
      ) as prev
      JOIN
      (
      SELECT c.id,c.name, SUM(co.invoicetotal) as total  
      FROM customers as c JOIN customerorders as co on co.customer_id = c.id  
      WHERE c.salesrep_id = 24  
      AND co.orderdate > CURDATE()
      GROUP by c.id ORDER BY total desc  
      ) as curr
      ON prev.id=curr.id
      

      【讨论】:

        【解决方案4】:

        我省略了日期计算,因为您是从代码生成的:

        SELECT c.id,c.name, 
            SUM(case when co.orderdate >= @LastMonthStartDate and co.orderdate < @CurrentMonthStartDate then co.invoicetotal else 0 end) as LastMonthTotal,
            SUM(case when co.orderdate between @CurrentMonthStartDate and CURDATE() then co.invoicetotal else 0 end) as CurrentMonthTotalToDate
        FROM customers as c 
        JOIN customerorders as co on co.customer_id = c.id 
        WHERE c.salesrep_id = 24 
           AND co.orderdate BETWEEN @LastMonthStartDate AND CURDATE() --remove this if you want customers that did not order in the last 2 months
        GROUP by c.id 
        order by total desc 
        

        【讨论】:

          【解决方案5】:

          我同意 JacobM 的观点,但提出了一种稍微不同的方法:

          SELECT
              c.id,
              c.name, 
              SUM(co1.invoicetotal) as PREV_MONTH, 
              SUM(co2.invoicetotal) as CUR_MONTH, 
          FROM
              customers as c, 
              customerorders as co1, 
              customerorders as co2
          WHERE 
              c.salesrep_id = 24
              and  co1.customer_id = c.id
              and  co2.customer_id = c.id
              AND co1.orderdate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()
              AND co2.orderdate > DATE_SUB(CURDATE(), INTERVAL 30 DAY)
          GROUP by c.id
          order by total desc
          

          不确定哪个更有效。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-11-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多