捕获SQL中的最新列值更改

时间:2012-12-04 13:59:25

标签: mysql sql greatest-n-per-group

如何使用一个SQL查询在一列中获取最新值更改的日期?

可能的数据库情况:

Date        State

2012-11-25  state one
2012-11-26  state one
2012-11-27  state two
2012-11-28  state two
2012-11-29  state one
2012-11-30  state one

因此结果应该以2012-11-29作为最新变化状态返回。如果我按状态值分组,我将在数据库中第一次获得该状态的日期。

查询将对表进行分组并显示状态,并在日期字段中创建该状态的最新日期。

根据给定的输入,输出将是

Date               State

2012-11-30        state one
2012-11-28        state two

7 个答案:

答案 0 :(得分:2)

这将使你获得最后一个状态:

-- Query 1
SELECT state
FROM tableX 
ORDER BY date DESC
  LIMIT 1 ;

封装上述内容,我们可以使用它来获取最后一次更改之前的日期:

-- Query 2
SELECT t.date
FROM tableX AS t
  JOIN
    ( SELECT state
      FROM tableX 
      ORDER BY date DESC
        LIMIT 1
    ) AS last
    ON last.state <> t.state
ORDER BY t.date DESC
    LIMIT 1 ;

然后使用它来查找最后一次更改发生的日期(或整行):

-- Query 3
SELECT a.date                         -- can also be used:   a.*
FROM tableX AS a 
  JOIN
    ( SELECT t.date
      FROM tableX AS t
        JOIN
          ( SELECT state
            FROM tableX 
            ORDER BY date DESC
              LIMIT 1
          ) AS last
          ON last.state <> t.state
      ORDER BY t.date DESC
          LIMIT 1
    ) AS b
    ON a.date > b.date
ORDER BY a.date
  LIMIT 1 ; 

SQL-Fiddle

中进行测试

使用MySQL变量的解决方案:

-- Query 4
SELECT date
FROM
  ( SELECT t.date
         , @r := (@s <> state) AS result 
         , @s := state AS prev_state
    FROM tableX AS t
      CROSS JOIN
        ( SELECT @r := 0, @s := '' 
        ) AS dummy 
    ORDER BY t.date ASC 
  ) AS tmp
WHERE result = 1
ORDER BY date DESC
  LIMIT 1 ;

答案 1 :(得分:0)

SELECT MAX(DATE) FROM YOUR_TABLE

以上答案似乎并不能满足OP的需要。

插入/更新触发后更新的答案

DELCARE @latestState varchar;
DELCARE @latestDate date;
CREATE TRIGGER latestInsertTrigger AFTER INSERT ON myTable
FOR EACH ROW
BEGIN
    IF OLD.DATE <> NEW.date THEN 
      SET @latestState = NEW.state 
      SET @latestDate = NEW.date
    END IF
END
;

CREATE TRIGGER latestUpdateTrigger AFTER UPDATE ON myTable
FOR EACH ROW
BEGIN 
    IF OLD.DATE = NEW.date AND OLD.STATE <> NEW.STATE THEN 
      SET @latestState = NEW.state 
      SET @latestDate = NEW.date
    END IF
END
;

您可以使用以下查询来添加/更新最新记录:

SELECT DATE, STATE FROM myTable
WHERE STATE = @latestState
OR DATE = @latestDate 
ORDER BY DATE DESC
;

结果:

DATE                                STATE
November, 30 2012 00:00:00+0000     state one
November, 28 2012 00:00:00+0000     state two
November, 27 2012 00:00:00+0000     state two

以上查询结果需要根据您的需要限制为2,3或n。

坦率地说,您似乎希望根据您提供的数据样本从两列获得最大值。假设您的州只随日期增加。只有我希望stateinteger:D 然后在两列上联合两个最大子查询就可以轻松解决它。仍然是字符串操作正则表达式可以找到状态列中的最大值。最后,这种方法需要limit x。但它仍然有 lope hole 无论如何,我花了一些时间来解决你的需求:$

答案 2 :(得分:0)

如果您添加另一列'更改日期时间',则可以使用插入NOW()的更新触发器来填充此列。如果您在更改的列上查询表顺序,它将首先结束。

CREATE TRIGGER `trigger` BEFORE UPDATE ON `table` 
FOR EACH ROW
BEGIN
SET ROW.changed = NOW();
END$$

答案 3 :(得分:0)

试试这个::

Select 
    MAX(`Date`), state from mytable 

    group by state

答案 4 :(得分:0)

我相信这就是答案:

SELECT 
    DISTINCT State AS State, `Date`
FROM 
    Table_1 t1
WHERE t1.`Date`=(SELECT MAX(`Date`) FROM Table_1 WHERE State=t1.State)

......和测试:

http://sqlfiddle.com/#!2/8b0d8/5

答案 5 :(得分:0)

如果你一直在使用postgres,你可以使用“LEAD .. OVER”来比较同一个表中的不同行。我还没有在mysql中找到相同的功能。

有点毛茸茸,但我想这会做:

select min(t1.date) from table_1 t1 where 
  (select count(distinct state) from table_1 where table_1.date>=t1.date)=1

基本上,这要求第一次没有找到任何后续值的状态变化。请注意,这个查询可能会对大型数据集造成严重影响....

答案 6 :(得分:0)

我认为你最好的选择是分析功能。试试这个 - 性能应该是好的:

SELECT *
FROM test
WHERE my_date = (SELECT MAX (my_date)
                FROM (SELECT MY_DATE
                        FROM (  SELECT MY_DATE,
                                       STATE,
                                       LAG (state) OVER (ORDER BY MY_DATE)
                                          lag_val
                                  FROM test
                              ORDER BY MY_DATE) a
                       WHERE state != lag_val))

在内部选择中,LAG函数获取STATE列中的先前值,而外部选择I中标记更改日期 - 滞后值不同于当前状态值的那些。在外面,我将从变更日期开始获取最新日期...我希望这就是您所需要的。