【问题标题】:MySQL - Join last row of related tableMySQL - 加入相关表的最后一行
【发布时间】:2013-03-04 14:48:41
【问题描述】:

我有一个问题,我已经搜索过但找不到可以提供任何帮助的答案。

有 3 个表:orderscustomersteams。每个订单都有一个客户和一个团队。我的问题是,对于每个客户,我都试图获得他们的总订单,然后是分配给他们最后一个订单的团队。

到目前为止我的查询(工作正常):

SELECT c.id, MAX(o.timestamp) AS "Last Order", COUNT(o.id) AS "Total Orders", SUM(o.price) AS "Total Spend"
FROM orders o
LEFT JOIN customers c ON o.customer = c.id
WHERE o.timestamp > '2012-01-01 00:00:00'
GROUP BY c.id
ORDER BY c.id

我不知道如何加入team.name 以获得他们下的最后一个订单,而不影响我的其余查询。

示例表和所需结果:

客户:

╔════╦═════════════╗
║ ID ║    NAME     ║
╠════╬═════════════╣
║  1 ║ John Smith  ║
║  2 ║ Jim Jimmers ║
╚════╩═════════════╝

团队:

╔════╦═════════════╗
║ ID ║    NAME     ║
╠════╬═════════════╣
║  1 ║ Red         ║
║  2 ║ Blue        ║
╚════╩═════════════╝

订单:

╔═══════╦═════════════════════╦══════════╦══════╦═══════╗
║  ID   ║       TIMESTAMP     ║ CUSTOMER ║ TEAM ║ VALUE ║
╠═══════╬═════════════════════╬══════════╬══════╬═══════╣
║ 34656 ║ 2012-03-04 14:23:44 ║        1 ║    2 ║    20 ║
║ 37345 ║ 2012-04-12 11:32:07 ║        2 ║    2 ║    25 ║
║ 38220 ║ 2012-07-18 09:53:54 ║        1 ║    2 ║    15 ║
║ 39496 ║ 2012-07-03 10:11:32 ║        1 ║    1 ║    38 ║
║ 41752 ║ 2012-09-17 19:34:05 ║        1 ║    2 ║     9 ║
║ 43734 ║ 2012-11-23 07:52:12 ║        2 ║    1 ║    20 ║
╚═══════╩═════════════════════╩══════════╩══════╩═══════╝

如何选择如下结果:

╔════╦═════════════╦═════════════════════╦═══════════╦══════════════╦═════════════╗
║ ID ║    NAME     ║      LAST_ORDER     ║ TEAM_NAME ║ TOTAL_ORDERS ║ TOTAL_SPEND ║
╠════╬═════════════╬═════════════════════╬═══════════╬══════════════╬═════════════╣
║  1 ║ John Smith  ║ 2012-09-17 19:34:05 ║ Blue      ║           4  ║          82 ║
║  2 ║ Jim Jimmers ║ 2012-11-23 07:52:12 ║ Red       ║           2  ║          45 ║
╚════╩═════════════╩═════════════════════╩═══════════╩══════════════╩═════════════╝

【问题讨论】:

  • 您能否像您在上一个问题中所做的那样提供具有所需结果的示例记录? :)
  • 团队表中需要多少个字段?如果这只是一个字段,那么简单的相关查询就可以了。
  • @JW。当然可以! @Bulat 我只需要分配给客户最后一个订单的团队的name
  • 为什么不用触发器?看看这个答案:stackoverflow.com/questions/26661314/…

标签: mysql sql


【解决方案1】:

您可以使用类似这样的查询:

select c.id,
  c.name,
  o1.Last_Order,
  t.name Team_Name,
  o3.Total_Orders,
  o3.Total_Spend
from customers c
inner join
(
  select max(timestamp) Last_Order,
    max(id) Last_id,
    customer
  from orders
  WHERE timestamp > '2012-01-01 00:00:00'
  group by customer
) o1
  on c.id = o1.customer
inner join orders o2
  on c.id = o2.customer
  and o1.Last_Order = o2.timestamp
  and o1.Last_id = o2.id
inner join teams t
  on o2.team = t.id
inner join
(
  select count(team) Total_Orders,
    sum(value) Total_Spend,
    customer
  from orders 
  WHERE timestamp > '2012-01-01 00:00:00'
  group by customer
) o3
  on c.id = o3.customer
WHERE o2.timestamp > '2012-01-01 00:00:00'

SQL Fiddle with Demo

【讨论】:

  • 感谢 bluefeet,但与 JW 一样,与我的原始帖子中的查询相比,我仍然获得了 40% 更少的行返回。
  • @BadHorsie 你能扩展你的数据样本,甚至用更多数据编辑 sql fiddle 吗?
【解决方案2】:

我喜欢使用group_concat 技巧来做到这一点:

SELECT c.id, MAX(o.timestamp) AS "Last, Order", COUNT(o.id) AS "Total Orders",
       SUM(o.price) AS "Total Spend",
       substring_index(group_concat(teamname order by o.timestamp desc), ',', 1) as LastTeam
FROM orders o left outer join
     customers c ON o.customer = c.id left outer join
     teams t
     on o.teamid = t.id
WHERE o.timestamp > '2012-01-01 00:00:00'
GROUP BY c.id
ORDER BY c.id

【讨论】:

  • 谢谢,我去看看。顺便说一句,您在substring_index 有一个错字,并且在“总支出”之后缺少逗号(我无法编辑它;太短了)。
  • 这似乎没有给我他们上次订单的团队。也许是他们的其他订单之一,但不是符合查询条件的最后一个订单。
  • 可能这个解决方案语法不正确,但这个概念是避免 SUB-SELECT 的最佳原因!谢谢!
【解决方案3】:

试试看,

SELECT  a.ID, 
        a.Name Customer_Name,
        c.TimeStamp Last_ORDER,
        c.Name AS Team_Name,
        COUNT(b.Customer) AS Total_Order,
        SUM(b.Value) AS Total_Spend
FROM    Customers a
        INNER JOIN Orders b
            ON a.ID = b.Customer
        INNER JOIN
        (
            SELECT  o.Customer, 
                    o.TimeStamp,
                    q.Name
            FROM    Orders o
                    INNER JOIN
                    (
                        SELECT  Customer, MAX(ID) max_ID
                        FROM    Orders
                        GROUP   BY Customer
                    ) p ON o.Customer = p.Customer AND
                            o.ID = p.max_ID
                    INNER JOIN Team q
                        ON o.Team = q.ID
        ) c ON a.ID = c.Customer
GROUP   BY a.ID, a.Name

【讨论】:

  • 谢谢,我现在正在尝试。不过,我需要在主查询中添加一些条件,以确保我只选择自 2012 年 1 月 1 日以来订购的客户。我尝试在最后一个 GROUP BY 之前添加 WHERE b.timestamp > '2012-01-01 00:00:00' 但它似乎不起作用,因为我得到的总行数大约是以前的一半。
  • 好的,你需要在最里面的查询中添加条件,SQLFiddle Demo (click here) 这是获取日期之间的查询,例如。 TIMESTAMP BETWEEN '2012-01-01 00:00:00' AND '2012-09-30 00:00:00'SQLFiddle Demo (click here)
  • 我得到的行数仍然比没有内部连接的原始查询少 40%。连接是否可能阻止返回某些行?原始查询结果应保持不变,只是为团队名称添加了额外的列。
  • 根据您的记录,如果我想在日期之间获取订单,结果会是什么,BETWEEN '2012-01-01 00:00:00' AND '2012-09-30 00:00:00'
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多