MySQL:从内联子查询返回多列

Posted

技术标签:

【中文标题】MySQL:从内联子查询返回多列【英文标题】:MySQL: Returning multiple columns from an in-line subquery 【发布时间】:2010-12-18 03:56:15 【问题描述】:

我正在创建一个 SQL 语句,它将返回每月的销售摘要。

摘要将列出日期、销售总数和销售总值的一些简单列。

但是,除了这些列之外,我还想再添加 3 个列,这些列将按花费的金额列出最佳客户的月份。对于这些列,我需要某种内联子查询,可以返回它们的 ID、名称和花费的金额。

我目前的工作是使用内联 SELECT 语句,但是,根据我对如何实现这些的了解,每个内联语句只能返回一列和一行。

为了在我的场景中解决这个问题,我当然可以创建 3 个单独的内联语句,但是,除了这看起来不切实际之外,它还会增加查询时间。

SELECT  
    DATE_FORMAT(OrderDate,'%M %Y') AS OrderMonth,
    COUNT(OrderID) AS TotalOrders, 
    SUM(OrderTotal) AS TotalAmount, 

    (SELECT SUM(OrderTotal) FROM Orders WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS TotalCustomerAmount,

    (SELECT OrderCustomerFK FROM Orders WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS CustomerID,

    (SELECT CustomerName FROM Orders INNER JOIN Customers ON OrderCustomerFK = CustomerID WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS CustomerName

FROM Orders     
GROUP BY DATE_FORMAT(OrderDate,'%m%y')
ORDER BY DATE_FORMAT(OrderDate,'%y%m') DESC

我怎样才能更好地构造这个查询?


完整答案

在对 Dave Barkers 解决方案进行了一些调整后,我为将来寻求帮助的任何人提供了最终版本。

Dave Barker 的解决方案与客户详细信息完美配合,但是,它使更简单的 Total Sales 和 Total Sale Amount 列得到了一些疯狂的数字。

SELECT  
        Y.OrderMonth,   Y.TotalOrders,  Y.TotalAmount,
        Z.OrdCustFK,  Z.CustCompany,    Z.CustOrdTotal, Z.CustSalesTotal   


 FROM 
        (SELECT
            OrdDate,
            DATE_FORMAT(OrdDate,'%M %Y') AS OrderMonth, 
            COUNT(OrderID) AS TotalOrders, 
            SUM(OrdGrandTotal) AS TotalAmount
            FROM Orders
            WHERE OrdConfirmed = 1    
            GROUP BY DATE_FORMAT(OrdDate,'%m%y') 
            ORDER BY DATE_FORMAT(OrdDate,'%Y%m') DESC)
    Y INNER JOIN 
        (SELECT 
            DATE_FORMAT(OrdDate,'%M %Y') AS CustMonth, 
            OrdCustFK, 
            CustCompany, 
            COUNT(OrderID) AS CustOrdTotal,
            SUM(OrdGrandTotal) AS CustSalesTotal 
        FROM Orders INNER JOIN CustomerDetails ON OrdCustFK = CustomerID
        WHERE OrdConfirmed = 1
        GROUP BY DATE_FORMAT(OrdDate,'%m%y'), OrdCustFK 
        ORDER BY SUM(OrdGrandTotal) DESC) 
    Z ON Z.CustMonth = Y.OrderMonth

GROUP BY DATE_FORMAT(OrdDate,'%Y%m')
ORDER BY DATE_FORMAT(OrdDate,'%Y%m') DESC

【问题讨论】:

关于完整解决方案的最后一点是,它将我原来的查询时间从大约 4 秒减少到 0.08 秒 完整的解决方案应该只在单独的答案中。 【参考方案1】:

将内联 SQL 移动为内连接查询。所以你会有类似...

SELECT  DATE_FORMAT(OrderDate,'%M %Y') AS OrderMonth, COUNT(OrderID) AS TotalOrders, SUM(OrderTotal) AS TotalAmount,  Z.OrderCustomerFK, Z.CustomerName, z.OrderTotal as CustomerTotal   
  FROM Orders     
  INNER JOIN (SELECT DATE_FORMAT(OrderDate,'%M %Y') as Mon, OrderCustomerFK, CustomerName, SUM(OrderTotal) as OrderTotal 
                FROM Orders 
               GROUP BY  DATE_FORMAT(OrderDate,'%M %Y'), OrderCustomerFK, CustomerName ORDER BY SUM(OrderTotal) DESC LIMIT 1) Z
          ON Z.Mon = DATE_FORMAT(OrderDate,'%M %Y')
    GROUP BY DATE_FORMAT(OrderDate,'%m%y'), Z.OrderCustomerFK, Z.CustomerName
    ORDER BY DATE_FORMAT(OrderDate,'%y%m') DESC

【讨论】:

【参考方案2】:

你也可以这样做:

SELECT 
    a.`y`,
    ( SELECT @c:=NULL ) AS `temp`,
    ( SELECT @d:=NULL ) AS `temp`,
    ( SELECT 
          CONCAT(@c:=b.`c`, @d:=b.`d`) 
      FROM `b`
      ORDER BY b.`uid` 
      LIMIT 1 ) AS `temp`,
    @c as c,
    @d as d
 FROM `a`

【讨论】:

谢谢。对于那些想知道的人,我理解这个想法是做一个内联选择 CONCATenating 所有你需要的,然后使用变量从中提取单独的列。我认为在某些情况下这更有效,因为子查询并不总是得到很好的优化...... 邪恶!不@phil_w,这个想法是假的,没有使用concat来利用它的变量设置。 @Julian 第一个赋值给 null 是不必要的,我认为。此外,使用case ... when 而不是concat 对于大字符串可能会更好。【参考方案3】:

试一试:

  SELECT CONCAT(o.order_month, ' ', o.order_year),
         o.total_orders,
         o.total_amount,
         x.sum_order_total,
         x.ordercustomerfk,
         x.customername
    FROM (SELECT MONTH(t.orderdate) AS order_month,
                 YEAR(t.orderdate) AS order_year
                 COUNT(t.orderid) AS total_orders, 
                 SUM(t.ordertotal) AS total_amount
            FROM ORDERS t
        GROUP BY MONTH(t.orderdate), YEAR(t.orderdate)) o
    JOIN (SELECT MONTH(t.orderdate) AS ordermonth,
                 YEAR(t.orderdate) AS orderyear
                 SUM(t.ordertotal) 'sum_order_total',
                 t.ordercustomerfk,
                 c.customername
            FROM ORDERS t
            JOIN CUSTOMERS c ON c.customerid = o.ordercustomerfk
        GROUP BY t.ordercustomerfk, MONTH(t.orderdate), YEAR(t.orderdate)) x ON x.order_month = o.order_month
                                                                            AND x.order_year = o.order_year
ORDER BY o.order_year DESC, o.order_month DESC

【讨论】:

抱歉,直到我发布了 Dave Barkers 解决方案的修订版,才注意到您的回答。但是,它看起来与最终对我有用的方式相同,所以谢谢。

以上是关于MySQL:从内联子查询返回多列的主要内容,如果未能解决你的问题,请参考以下文章

子查询(章节摘要)

MySql复合查询

MySQL复合查询

MySQL复合查询

MySQL 复合查询

MySQL 复合查询