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:从内联子查询返回多列的主要内容,如果未能解决你的问题,请参考以下文章