【问题标题】:How can I write a trigger that updates rows in the same table, before the insert is commited?在提交插入之前,如何编写一个触发器来更新同一个表中的行?
【发布时间】:2013-11-20 03:32:08
【问题描述】:

我的数据库中有一个名为 stockpricehistory 的表,它跟踪库存项目的价格变化,并包含以下字段:

  • 股票编号
  • 价格
  • DateStart(引入该特定价格的时间)
  • DateEnd(当该特定价格停止使用时)。

DateStart 默认为 CURRENT_TIMESTAMP,DateEnd 默认为空,就好像没有 DateEnd 值一样,那么该行中的价格就是该股票的当前价格。

现在,我如何(我假设它是通过触发器)做到这一点,以便每当我为特定库存项目插入新行时,它会更新该库存项目的最后一个当前行(即匹配的行该库存项目,其中 DateEnd 设置为 NULL)以匹配刚刚为要插入的新行提供的 DateStart 值,如下所示:

这是表格的初始状态:

  1. 1,2.99,2013-11-19 18:49:24,NULL

然后,当为 Stock (ID 1) 的该项目插入新行时,结果如下:

  1. 1,4.99,2013-11-20 12:00:00,NULL

  2. 1,2.99,2013-11-19 18:49:24,2013-11-20 12:00:00

理论上,它应该只需要更新一行,因为每个股票ID只有一行没有结束日期,也就是当前价格的行。

我认为这将通过 BEFORE INSERT 触发器完成,但我很可能错了。

【问题讨论】:

    标签: mysql sql triggers


    【解决方案1】:

    正如@Filipe Silva 所说,您无法修改在该表上调用的触发器中的表。

    您可以通过为股票和股票价格历史记录单独的表格来解决此问题,这在任何情况下都可能是一个好主意。 stock 表包含每个库存项目的一行及其当前价格,并且该表上的触发器维护 stockpricehistory 中的记录,因为 stock 中的行被插入或更新。

    http://sqlfiddle.com/#!2/55c626/1

    create table stock (
      stockId int primary key,
      price numeric(5, 2));
    
    create table stockpricehistory (
      stockId int,
      price numeric(5,2),
      dateStart datetime,
      dateEnd datetime);
    
    create trigger t_si before insert on stock
    for each row
      insert into stockpricehistory values (new.stockId, new.price, current_timestamp, null);
    
    create trigger t_su before update on stock
    for each row begin
      update 
        stockpricehistory 
      set
        dateEnd = current_timestamp
      where
        stockId = new.stockId and
        dateEnd is null;
      insert into stockpricehistory values (new.stockId, new.price, current_timestamp, null);
    end;
    

    【讨论】:

    • 如果我有声望,我会支持你,非常感谢 :) 那个更好,我最初被说服将所有定价都保留在股票表之外,并保留所有在价格历史表中,但仅在股票表中显示当前价格对我来说很好,谢谢:)
    【解决方案2】:

    根据documentation

    在存储的函数或触发器中,不允许修改 已被(用于读取或写入)的表 调用函数或触发器的语句。

    您始终可以在插入后从您插入的位置进行更新。

    要更新它,你可以这样做:

    UPDATE stockpricehistory s
    INNER JOIN (
      SELECT stockID,
        MAX(dateStart) AS maxDate
      FROM stockpricehistory
      WHERE StockID = 1
        AND DateEnd IS NULL
      ) a ON s.StockID = a.StockID    
    SET s.dateEnd = a.maxDate
    WHERE s.DateEnd IS NULL
      AND s.dateStart != a.maxDate
    

    这是为了让您更新 dateEnd NULL 的行之一,而不是 max(dateStart) 的行。

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-14
      • 1970-01-01
      • 2017-01-22
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      相关资源
      最近更新 更多