【问题标题】:How to select latest date from this query (not in a existing table)?如何从此查询中选择最新日期(不在现有表中)?
【发布时间】:2018-01-02 13:43:11
【问题描述】:

我想显示每个任务的最新操作。这是表(虚拟数据但结构相同):

//t_task
task_id             task_name
     A1              PC  Proc
     A2         Printer  Proc
     A3       Stationery Proc

//t_task_d
task_id           assigned_to
     A1                  John
     A1                 Sally
     A2                  John
     A3                 Sally

//t_act
no       act_id       act_date     task_id
 1           C1     2017-07-10          A1
 2           C2     2017-07-14          A1
 3           C3     2017-07-17          A1
 4           C1     2017-07-21          A2

//t_act_d
act_id       act_name
    C1      Surveying 
    C2       Contract
    C3      Execution

根据上面的表格,我想创建某种报告。这是我的预期输出:

no            task_name   dates_of_act       status
 1              PC Proc     2017-07-17    Execution
 2         Printer Proc     2017-07-21    Surveying
 3      Stationery Proc         -           Pending /*if it's NULL, then it should be pending, but I can change this in the PHP section*/

这是我最近的当前查询:

SELECT 
    t_task.task_name, 
    DATE(t_act.act_date) AS 'dates_of_act', 
    t_act_d.act_name 
FROM t_task 

INNER JOIN t_task_d ON t_task.task_id = t_task_d.task_id
LEFT OUTER JOIN t_act ON t_task.task_id = t_act.task_id 
LEFT OUTER JOIN t_act_d ON t_act.act_id = t_act_d.act_id

GROUP BY t_task.task_id 
ORDER BY t_act.act_date ASC

我的查询结果是:

no            task_name   dates_of_act       status
 1              PC Proc     2017-07-10    Surveying
 2         Printer Proc     2017-07-21    Surveying
 3      Stationery Proc         -           Pending

注意
我更喜欢速度,因为数据量很大。如果可能的话,我也尽量避免子查询

【问题讨论】:

  • 如果你喜欢速度,你应该小心按字段索引你的订单。
  • @HerrNentu' 好吧,我愿意接受任何建议。

标签: php mysql sql sql-server


【解决方案1】:

我觉得可以。

select
  t_task.task_id,
  t_task.task_name,
  latest_action.act_date,
  IFNULL(t_act_d.act_name, 'Pending') as act_name
from
  t_task
  left outer join (
    select
      @row_num := IF(@prev_value=concat_ws('', t_act.task_id),@row_num+1, 1) as row_number,
      t_act.task_id,
      t_act.act_id,
      t_act.act_date,
      @prev_value := concat_ws('', t_act.task_id) as z
    from
      t_act,
      (select @row_num := 1) x,
      (select @prev_value := '') y
    order by
      t_act.task_id,
      t_act.act_date desc
  ) as latest_action on
    t_task.task_id = latest_action.task_id
  left outer join t_act_d on
    latest_action.act_id = t_act_d.act_id
where
  latest_action.row_number = 1 or
  latest_action.row_number is null
order by
  case when latest_action.act_date is null then '9999-01-01' else latest_action.act_date end

您提供的数据的结果是:

+---------+-----------------+------------+-----------+
| task_id | task_name       | act_date   | act_name  |
+---------+-----------------+------------+-----------+
| A1      | PC  Proc        | 2017-07-17 | Execution |
| A2      | Printer  Proc   | 2017-07-21 | Surveying |
| A3      | Stationery Proc | NULL       | Pending   |
+---------+-----------------+------------+-----------+

我更熟悉 T-SQL,我会在其中使用 row_number() 窗口函数。这个想法是让 row_number 字段显示每行的排名,根据它是否是最近的(值 1)、第二最近的(值 2)等每个任务的操作。每个任务的最新操作的 row_number 为 1,因此您可以通过在此 latest_action 子查询中过滤 row_number = 1 来获得这些结果。

因为latest_action 子查询整体运行一次,而不是每行一次,所以它不会对性能造成太大影响。不幸的是,我不能保证整个变量设置/递增的事情不会对性能造成太大影响,这是我第一次在 MySQL 中使用这种逻辑,我不知道它的性能如何。

如何重现 T-SQL 的 row_number() 功能的逻辑来自这里:ROW_NUMBER() in MySQL

【讨论】:

  • 嗯,这很复杂。处理十万条数据的速度够快吗?
  • 数十万行应该不是问题。可能有几千万。如果它在 Microsoft SQL Server 中会更干净,但据我了解,您尝试解决的问题需要某种排序功能。如果您知道每个时间戳只有一个操作,那么可能会有更简单的解决方案。如果你不能保证,那么这可能是你能得到的最好的。
  • 最好的方法是尝试一下;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-20
  • 1970-01-01
  • 1970-01-01
  • 2014-01-24
  • 2016-06-15
  • 1970-01-01
  • 2020-09-03
相关资源
最近更新 更多