简体   繁体   English

在MySQL中将上一行子查询转换为联接

[英]Converting Previous Row Subquery into a Join in MySQL

I have policy information in a policy table. 我在策略表中有策略信息。 Each row represents the policy status at a certain time (the time is stored in an updated_on column). 每行表示特定时间的策略状态(时间存储在updated_on列中)。 Each row belongs to a policy iteration (multiple policy rows can belong to a single policy iteration). 每行都属于一个策略迭代(多个策略行可以属于一个策略迭代)。 I want to look at status changes from row to row within a policy iteration. 我想查看策略迭代中各行之间的状态变化。

The policy table: 策略表:

CREATE TABLE `policy` (
  `policy_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `policy_iteration_id` int(10) unsigned NOT NULL,
  `policy_status_id` tinyint(3) unsigned NOT NULL,
  `updated_on` datetime NOT NULL,
  PRIMARY KEY (`policy_id`),
  KEY `policy_iteration_idx` (`policy_iteration_id`),
  KEY `policy_status_updated_idx` (`policy_status_id`,`updated_on`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

I want to be able to pass a date range and a "from" status and a "to" status and return the policy data for the "to" row. 我希望能够传递日期范围以及“从”状态和“至”状态,并返回“至”行的策略数据。 So in pseudo code, I need to group by policy iteration, find rows that satisfy the data range and the "to" status, then look at the previous row within that policy iteration to see if it has the "from" status. 因此,在伪代码中,我需要按策略迭代分组,找到满足数据范围和“至”状态的行,然后查看该策略迭代中的上一行,以查看其是否具有“从”状态。 If so, return the "to" row's information. 如果是这样,则返回“至”行的信息。

This is the query I came up with: 这是我想出的查询:

SELECT
    pto.policy_iteration_id,
    pto.policy_id,
    pto.updated_on,
FROM
    policy AS pto
WHERE
    pto.updated_on >= $from_date AND
    pto.updated_on <= $to_date AND
    pto.policy_status_id = $to_status_id AND
    $from_status_id = 
    (SELECT
        pfrom.policy_status_id
    FROM
        policy AS pfrom
    WHERE
        pfrom.policy_iteration_id = pto.policy_iteration_id AND
        pfrom.policy_id < pto.policy_id
    ORDER BY
        pfrom.policy_id DESC
    LIMIT
        1);

This query works but is very inefficient because of the subquery having to be executed for each row. 该查询有效,但是效率非常低,因为必须为每一行执行子查询。 I'd like to make it more efficient by using subquery join(s) but I can't figure out how. 我想通过使用子查询联接来提高效率,但是我不知道怎么做。

Any help would be appreciated. 任何帮助,将不胜感激。 Thanks! 谢谢!

UPDATE #1 更新1

To help explain what I'm trying to do, here is an example data set: 为了帮助解释我要做什么,这是一个示例数据集:

+-----------+---------------------+------------------+---------------------+
| policy_id | policy_iteration_id | policy_status_id | updated_on          |
+-----------+---------------------+------------------+---------------------+
|    323705 |               27230 |                6 | 2014-08-01 10:27:11 |
|    325028 |               27230 |                2 | 2014-08-01 17:12:28 |
|    323999 |               27591 |                2 | 2014-08-01 12:07:31 |
|    324008 |               27591 |                6 | 2014-08-01 12:10:23 |
|    325909 |               27591 |                2 | 2014-08-02 14:59:12 |
|    327116 |               29083 |                6 | 2014-08-04 12:09:16 | 
|    327142 |               29083 |                6 | 2014-08-04 12:19:00 |
|    328067 |               29083 |                2 | 2014-08-04 17:58:41 |
|    327740 |               29666 |                3 | 2014-08-04 16:16:55 |
|    327749 |               29666 |                3 | 2014-08-04 16:19:01 |
+-----------+---------------------+------------------+---------------------+

Now if I run the query where from_date = '2014-08-02 00:00:00', to_date = '2014-08-05 00:00:00', from_status = 6 and to_status = 2, the result should be: 现在,如果我运行from_date ='2014-08-02 00:00:00',to_date ='2014-08-05 00:00:00',from_status = 6和to_status = 2的查询,结果应为:

+-----------+---------------------+------------------+---------------------+
| policy_id | policy_iteration_id | policy_status_id | updated_on          |
+-----------+---------------------+------------------+---------------------+
|    325909 |               27591 |                2 | 2014-08-02 14:59:12 |
|    328067 |               29083 |                2 | 2014-08-04 17:58:41 |
+-----------+---------------------+------------------+---------------------+

Those two rows have a row with the selected "to_status" of 2 within the stated time period and have their previous row with the "from_status" of 6. 这两行在指定的时间段内具有选择的“ to_status”为2的行,而其前一行的“ from_status”为6。

I don't believe joining a MAX policy id with a GROUP BY of policy_iteration_id will do the job since that would return the rows that are most recent, not the row that is previous to the row with the "to_status". 我不认为可以将MAX策略ID与GROUP BY的policy_iteration_id结合使用,因为这样做会返回最新的行,而不是返回带有“ to_status”的行之前的行。

Any further help would be appreciated. 任何进一步的帮助,将不胜感激。 Thanks! 谢谢!

You can use use max from.policy_id where from.policy_id < to.policy_id to help get the previous row as a set. 您可以使用use max from.policy_id where from.policy_id < to.policy_id有助于将上一行作为一个集合。

select
        p.policy_iteration_id,
        p.policy_id,
        p.updated_on
from 
    policy f
        inner join (
    select
        p.policy_iteration_id,
        p.policy_id,
        p.updated_on,
        max(f.policy_id) as prev_policy_id
    from
        policy p
            inner join 
        policy f 
            on f.policy_iteration_id = p.policy_iteration_id and
               f.policy_id < p.policy_id
    where
        p.updated_on >= $from_date and
        p.updated_on <= $to_date and
        p.policy_status_id = $to_status_id
    group by
        p.policy_iteration_id,
        p.policy_id,
        p.updated_on
) p
        on p.prev_policy_id = f.policy_id
where
    f.policy_status_id = $from_status_id

In a database with window functions there are simpler ways of achieving this. 在具有窗口功能的数据库中,有更简单的方法可以实现此目的。

Example SQLFiddle 示例SQLFiddle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM