Mysql 如何使用SQL查询在此表中找到正确的前一状态行?

Mysql 如何使用SQL查询在此表中找到正确的前一状态行?,mysql,sql,Mysql,Sql,设想一个用于数据输入的工作流。一些表格被输入到系统中,经过审核,并有望获得批准。但是,经理可能会拒绝它们,并且必须重新输入 因此,理想的工作流程如下所示: form_id status updated_by updated_at 1 received Bob (timestamp) 1 entered Bob (timestamp) 1 approved Susan (timestamp) 2

设想一个用于数据输入的工作流。一些表格被输入到系统中,经过审核,并有望获得批准。但是,经理可能会拒绝它们,并且必须重新输入

因此,理想的工作流程如下所示:

form_id status     updated_by updated_at
1       received   Bob        (timestamp)
1       entered    Bob        (timestamp)
1       approved   Susan      (timestamp)
2       received   Bob        (timestamp)
2       entered    Bob        (timestamp)
2       rejected   Susan      (timestamp)
2       entered    Carla      (timestamp)
2       rejected   Susan      (timestamp)
2       entered    Sam        (timestamp)
2       approved   Susan      (timestamp)
接收>输入>批准

但这可能发生:

接收>输入>拒绝>输入>拒绝>批准

在每个阶段,我们都会记录谁将表单更新到当前状态-谁输入、谁拒绝或谁批准了表单。因此表单状态表如下所示:

form_id status     updated_by updated_at
1       received   Bob        (timestamp)
1       entered    Bob        (timestamp)
1       approved   Susan      (timestamp)
2       received   Bob        (timestamp)
2       entered    Bob        (timestamp)
2       rejected   Susan      (timestamp)
2       entered    Carla      (timestamp)
2       rejected   Susan      (timestamp)
2       entered    Sam        (timestamp)
2       approved   Susan      (timestamp)
我想做的是:写一份拒绝报告。我希望每一次被拒绝都有一行,加入到这一行中,我想看看谁做了被拒绝的工作

作为一个人,我可以看到,对于状态为“拒绝”的给定状态行,将告诉我谁做了错误工作的行将是

共享相同的表单\u id和 具有最接近拒绝的先前时间戳。 但我很难告诉你


有人知道如何构造此查询吗?

您希望获得被拒绝的时间戳,然后根据时间戳找出出现在它前面的条目。我假设时间戳实际上包含一个日期/时间,而不是一个完全不同的SQLServer时间戳字段

declare @rejectedTimestamp timestamp

select @rejectedTimestamp = timestamp
from table
where status = 'rejected'

select top 1 *
from table
where timestamp < @rejectedtimestamp
order by timestamp desc

一个次级选择最终为我工作

SELECT 
  `s1`.`form_id`, 
  (
    SELECT 
      `s2`.`updated_by`
    FROM 
      statuses s2
    WHERE 
      `s2`.`form_id` = `s1`.`form_id`
      AND
        `s2`.`updated_at` < `s1`.`updated_at` 
    ORDER BY 
      `s2`.`updated_at` DESC
    LIMIT 1
  ) AS 'made_rejected_change'
FROM 
  statuses s1
WHERE
  `s1`.`status` = 'rejected'

另一种解决方案,这次使用subselect而不是相关子查询:

SELECT
  w1.*,
  w2.entered_by
FROM (
  SELECT
    wr.form_id,
    wr.updated_at AS rejected_at,
    wr.updated_by AS rejected_by,
    MAX(we.updated_at) AS entered at
  FROM workflow wr
    INNER JOIN workflow we ON we.status = 'entered'
      AND wr.form_id = we.form_id
      AND wr.updated_at > we.updated_at
  WHERE wr.status = 'rejected'
  GROUP BY
    wr.form_id,
    wr.updated_at,
    wr.updated_by
) w1
  INNER JOIN workflow w2 ON w1.form_id = w2.form_id
    AND w1.entered_at = w2.updated_at

subselect列出了所有拒绝者和前面输入的时间戳。然后再次连接该表,以提取与输入的时间戳对应的名称。

标准SQL时间戳同时包含日期和时间。Microsoft SQL Server Transact-SQL时间戳与标准SQL时间戳不同。这就是我试图在上面创建的区别。由于OP发布问题的方式表明时间戳包含一些有意义的数据,因此我以同样的方式回答了问题,您应该将术语SQL timestamp更改为SQL Server timestamp以明确这一点。标准SQL时间戳由日期和时间组成。但这与问题无关,因为它涉及MySQL。