我想展示每项任务的最新动作。这是表格(虚拟数据但结构相同):
//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
注意
我更喜欢速度,因为数据量很大。我也尽量避免使用子查询
答案 0 :(得分: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