【问题标题】:How to return results that relate across 3 tables efficiently MySQL如何有效地返回与 3 个表相关的结果 MySQL
【发布时间】:2016-01-09 19:38:16
【问题描述】:

你好,

我有以下 3 个表:order、manifest 和 tracking_updates。现在,每个订单都有一个名为 manifest_id 的外键,它引用清单表。清单中可以包含多个订单。 tracking_updates 表有一个称为 order_id 的外键,它引用了 order 表。

现在,清单表包含一个名为 upload_date 的列。该列,upload_date 是我需要使用的列,以确定订单是否在过去 30 天内上传。

tracking_update 表可以包含每个订单的许多更新,因此,我必须返回符合以下条件的每个订单的最新跟踪更新状态:

1. orders < 30 days, any delivery status 
2. orders > 30 days, not delivered

请看下表

**Order**

ID |  manifest_id

1  |  123

2  |  123

3  |  456

**Manifest**:

ID |  upload_date

123  |  2015-12-15 09:31:12

456  |  2015-10-13 09:31:12

**Tracking Update**:

order_id  | status_type | last_updated

1         |  M          | 2015-12-15 00:00:00

1         |  I          | 2015-12-16 07:20:00

1         |  D          | 2015-12-17 15:20:00

2         |  M          | 2015-12-15 00:00:00

2         |  D          | 2015-12-16 15:20:00

3         |  M          | 2015-10-13 00:00:00

3         |  I          | 2015-10-14 12:00:00

3         |  E          | 2015-10-15 13:50:00

这是上面订单的结果集的样子

**Result Set**

order_id  | manifest_id | latest_tracking_update_status

1         | 123         | D

2         | 123         | D

3         | 456         | E

如您所见,订单 1、2 被分配到清单 123,并且清单是在过去 30 天内上传的,并且它们的最新跟踪更新显示“D”表示已交付。所以这两个订单应该包含在结果集中。

订单 3 早于 30 天,但根据最新的 tracking_update status_type 尚未交付,因此它应该显示在结果集中。

现在,tracking_update 表以及所有订单的超过 100 万次更新。所以我真的要在这里提高效率

目前,我有以下疑问。

查询 #1 返回过去 30 天内上传的订单及其对应的最新跟踪更新

SELECT 
fgw247.order.id as order_id,
    (SELECT 
        status_type
    FROM 
        tracking_update as tu
    WHERE 
        tu.order_id = order_id
    ORDER BY 
        tu.ship_update_date DESC
    LIMIT 
        1
    ) as latestTrackingUpdate
FROM 
    fgw247.order, manifest
WHERE
    fgw247.order.manifest_id = manifest.id 
AND
    upload_date >= '2015-12-12 00:00:00'

查询 #2 返回 tracking_update 表中每个订单的 order_id 和最新跟踪更新:

SELECT tracking_update.order_id,
    substring_index(group_concat(tracking_update.status_type order by tracking_update.last_updated), ',', -1)
FROM 
    tracking_update
WHERE 
    tracking_update.order_id is not NULL
GROUP BY tracking_update.order_id

我只是不确定如何组合这些查询来获得符合条件的订单:

  1. 订单
  2. 订单 > 30 天,未送达

任何想法都将不胜感激。

* 更新 *

由于选择了答案,这是当前查询:

select 
    o.id, t.maxudate, tu.status_type, m.upload_date
from 
    (select order_id, max(last_updated) as maxudate from tracking_update group by order_id) t
inner join 
    tracking_update tu on t.order_id=tu.order_id and t.maxudate=tu.last_updated
right join 
    fgw247.order o on t.order_id=o.id
left join 
    manifest m on o.manifest_id=m.id
where 
    (tu.status_type != 'D' and tu.status_type != 'XD' and m.upload_date <='2015-12-12 00:00:00') or m.upload_date >= '2015-12-12 00:00:00'
LIMIT 10

更新

这是连接三个表的当前查询,效率很高

SELECT 
    o.*, tu.*
FROM
    fgw247.`order` o
JOIN
    manifest m
ON
    o.`manifest_id` = m.`id` 

JOIN
    `tracking_update` tu
ON
    tu.`order_id` = o.`id` and tu.`ship_update_date` = (select max(last_updated) as last_updated from tracking_update where order_id = o.`id` group by order_id)
WHERE
    m.`upload_date` >= '2015-12-14 11:50:12' 
    OR 
        (o.`delivery_date` IS NULL AND m.`upload_date` < '2015-12-14 11:50:12')
LIMIT 100

【问题讨论】:

  • 你可以做的是加入所有的表在他们各自的条件下,如 ID、ManifestID 和 OrderID,然后选择 Upload_Date 和 Last_updated 作为结果并放入一些临时表。之后,您可以使用条件语句检查日期的差异,例如 Select Case [Last_updated -Upload_Date ] >30 then D else P
  • 这不会超过最大连接大小吗?跟踪更新表超过 100 万条记录。

标签: mysql sql join


【解决方案1】:

有一个子查询,它从跟踪表中返回每个订单的最新更新日期。在跟踪、订单和清单表上加入此子查询,以获取详细信息并根据 where 子句中的上传日期进行过滤:

select o.order_id, t.maxudate, tu.status_type, m.upload_date
from (select order_id, max(update_date) as maxudate from tracking_update group by order_id) t
inner join tracking_update tu on t.order_id=tu.order_id and t.maxudate=tu.update_date
right join orders o on t.order_id=o.order_id
left join manifests m on o.manifest_id=m.manifest_id
where (tu.status_type<>'D' and curdate()-m.upload_date>30) or curdate()-m.upload_date<=30

在 where 子句中使用 union 查询而不是 or 条件可能更有效。

【讨论】:

  • 虽然我同意这个概念,但这实际上并没有运行
  • 请提供一些有意义的反馈,例如您运行的确切查询、收到的错误消息或遇到的意外行为。
  • 我在 m.upload_date 之后收到语法错误。所以我放了一个逗号,但是我在内部连接上收到了一个语法错误
  • 我错过了括号前的from关键字,我更新了答案
  • 谢谢,但我现在收到:错误代码:1054。“字段列表”中的“o.order_id”列未知。我更新了我的问题以显示我运行的查询
【解决方案2】:

您可以使用第二个查询结果执行JOIN,例如

SELECT 
fgw247.order.id as order_id,
xx.some_column,
    (SELECT 
        status_type
    FROM 
        tracking_update as tu
    WHERE tu.order_id = order_id
    ORDER BY 
        tu.ship_update_date DESC
    LIMIT 
        1
    ) as latestTrackingUpdate
FROM 
    fgw247.order JOIN manifest
ON fgw247.order.manifest_id = manifest.id 
JOIN (
SELECT tracking_update.order_id,
    substring_index(group_concat(tracking_update.status_type order by tracking_update.last_updated), ',', -1) AS some_column
FROM 
    tracking_update
WHERE 
    tracking_update.order_id is not NULL
GROUP BY tracking_update.order_id ) xx ON xx.order_id = fgw247.order.id

WHERE upload_date >= '2015-12-12 00:00:00'

【讨论】:

  • 我不这么认为...... 为什么会这样?
  • 它为每个订单 ID 运行一个子查询。
  • 感谢您的回复。我从初始选择中删除了子查询,因为当您加入第二个查询时它是多余的。是的,这确实可以连接两个表,但是超过 30 天未交付的订单呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-11
  • 2013-08-30
相关资源
最近更新 更多