CakePHP(子)查询获取每个组的最新记录

时间:2013-11-11 14:12:22

标签: mysql cakephp-2.3

在一个项目中,我管理的发票状态在其整个生命周期中都会发生变化。状态更改保存在另一个与此类似的数据库表中:

|id|invoice_id|user_id|old_status_id|new_status_id|change_date        |
-----------------------------------------------------------------------
| 1|         1|      1|            1|            3|2013-11-11 12:00:00|
| 2|         1|      2|            3|            5|2013-11-11 12:30:00|
| 3|         2|      3|            1|            2|2013-11-10 08:00:00|
| 4|         1|      1|            5|            6|2013-11-11 13:10:00|
| 5|         2|      2|            2|            5|2013-11-10 09:00:00|

对于每张发票,我想检索上次状态更改。因此,结果应包含带有ID 4和5的记录。

|id|invoice_id|user_id|old_status_id|new_status_id|change_date        |
-----------------------------------------------------------------------
| 4|         1|      1|            5|            6|2013-11-11 13:10:00|
| 5|         2|      2|            2|            5|2013-11-10 09:00:00|

如果我按invoice_id分组并使用max(change_date),我将检索最年轻的日期,但其他字段的字段值不会从包含该组中最年轻日期的记录中获取。

这对我来说是挑战#1。

挑战#2将是使用CakePHP的方法实现查询,如果可能的话。

挑战#3将结果过滤到属于当前用户的那些记录。因此,如果当前用户的id为1,则结果为

|id|invoice_id|user_id|old_status_id|new_status_id|change_date        |
-----------------------------------------------------------------------
| 4|         1|      1|            5|            6|2013-11-11 13:10:00|

如果他或她有用户ID 2,则结果为

|id|invoice_id|user_id|old_status_id|new_status_id|change_date        |
-----------------------------------------------------------------------
| 5|         2|      2|            2|            5|2013-11-10 09:00:00|

对于ID为3的用户,结果为空。

换句话说,我希望找到用户所做的所有最新更改,无论他是否是最后一个做出更改的人。相反,我想找到所有发票更改,其中该用户是迄今为止做出更改的用户。我的动机是,我想让用户撤消他的更改,这只有在他之后没有其他用户执行了其他更改时才有可能。

1 个答案:

答案 0 :(得分:0)

如果有人需要答案

严格关注:

我想查找所有发票变更,其中该用户是目前为止进行更改的最后一位用户

将SQL写为

SELECT foo.*
FROM foo
LEFT JOIN foo AS after_foo
  ON foo.invoice_id = after_foo.invoice_id
    AND foo.change_date < after_foo.change_date
WHERE after_foo.id IS NULL
  AND foo.user_id = 1;

使用Cakephp JOIN中的find子句实现。


建议算法的SQL类似于:

SELECT foo.*
FROM foo
JOIN (SELECT invoice_id, MAX(change_date) AS most_recent
      FROM foo
      GROUP BY invoice_id) AS recently
  ON recently.invoice_id = foo.invoice_id
    AND recently.most_recent = foo.change_date
WHERE foo.user_id = 1;