Trigger on insert for each new record

I have a table with this structure

ITEM_ID VARCHAR(255) NOT NULL PRIMARY KEY,
COST1 FLOAT NOT NULL,
COST2 FLOAT NOT NULL,
PRICE1 FLOAT NOT NULL,
PRICE2 FLOAT NOT NULL,
VALID_FROM DATE NOT NULL PRIMARY KEY,
VALID_UNTIL DATE NULL,

The default value for VALID_UNTIL is ‘2099-12-31’

I need to create a trigger in this table so that when I insert new records the most recent record in the table updates the value of VALID_UNTIL to be the same as the value of VALID_FROM of the record being inserted as long as ITEM_ID is the same. And when there is no record matching on the table I want it to just insert the new record.

And I want the trigger to apply for every new record individually from oldest to newest by the VALID_FROM column being inserted.

I already tried this query, but the trigger applies to all the records being inserted at the same time so the VALID_UNTIL result for every record is ‘2099-12-31’

CREATE TRIGGER trg_update_valid_until
ON cal.MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
    FROM cal.MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
        AND t.VALID_UNTIL = '2099-12-31'
        AND t.VALID_FROM < i.VALID_FROM;
END;

Here is some sample data as well

INSERT INTO cal.MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008209, 4062.7, 4062.7, 5803.85, 6732.47, '2024-12-01'),
(2008209, 4119.57, 4119.57, 5885.09, 6826.7, '2024-12-02'),
(2008209, 4150.85, 4150.85, 5929.78, 6878.54, '2024-12-06');

New contributor

Santiago C is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

10

For a more robust solution, don’t store VALID_UNTIL because VALID_FROM is enough. When you need to obtain the prices for a given date just use the following query:

select top 1 *
from MA_COSTS
where ITEM_ID = @ItemId
and VALID_FROM <= @DateOfInterest
order by VALID_FROM desc;

There is no advantage in storing VALID_UNTIL – it just makes things more complicated.

And ensure you change the datatype of your columns – DO NOT USE FLOAT to store money! Float is an inaccurate datatype intended for scientific data… you need a precise datatype, you don’t want to lose money due to the behaviour of float. Use something like decimal(18,2)

0

I like Dale K’s idea of eliminating the VALID_UNTIL column and using the CROSS APPLY (SELECT TOP 1 ...) pattern for looking up prices.

However, if that isn’t an option, the following should satisfy your needs.

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE tPrior
    SET VALID_UNTIL = i.VALID_FROM
    FROM inserted i
    CROSS APPLY (
        -- Locate immediately prior cost row for this item
        SELECT TOP 1 t.*
        FROM MA_COSTS t
        WHERE t.ITEM_ID = i.ITEM_ID
        AND t.VALID_FROM < i.VALID_FROM
        ORDER BY t.VALID_FROM DESC
    ) tPrior
    WHERE tPrior.VALID_UNTIL = '2099-12-31'
    --or perhaps: WHERE tPrior.VALID_UNTIL > i.VALID_FROM
END;

For each inserted row, the prior row is identified and updated as needed.

An index in MA_COSTS(ITEM_ID, VALID_FROM) is needed to support direct lookup of the related rows using an index seek. If (ITEM_ID, VALID_FROM) is the primary key, no separate index is needed.

If you might be inserting rows with VALID_FROM values in the middle of the existing range, a second update may be needed to set the VALID_UNTIL values for the newly added row(s).

...
    UPDATE tCurrent
    SET VALID_UNTIL = tNext.VALID_FROM
    FROM inserted i
    JOIN MA_COSTS tCurrent
        ON tCurrent.ITEM_ID = i.ITEM_ID
        AND tCurrent.VALID_FROM = i.VALID_FROM
    CROSS APPLY (
        -- Locate immediately following cost row for this item
        SELECT TOP 1 t.*
        FROM MA_COSTS t
        WHERE t.ITEM_ID = i.ITEM_ID
        AND t.VALID_FROM > i.VALID_FROM
        ORDER BY t.VALID_FROM
    ) tNext
    WHERE tCurrent.VALID_UNTIL > tNext.VALID_FROM

Note that the above does not handle updates or deletes that may require adjustments to other rows.

Sample results after multiple insert operations with rows presented in a mixed order:

ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008209 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008209 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-03
2008209 3333.33 3333.33 3333.33 3333.33 2024-12-03 2024-12-04
2008209 4444.44 4444.44 4444.44 4444.44 2024-12-04 2024-12-05
2008209 5555.55 5555.55 5555.55 5555.55 2024-12-05 2024-12-06
2008209 4150.85 4150.85 5929.78 6878.54 2024-12-06 2024-12-07
2008209 7777.77 7777.77 7777.77 7777.77 2024-12-07 2024-12-08
2008209 8888.88 8888.88 8888.88 8888.88 2024-12-08 2024-12-09
2008209 9999.99 9999.99 9999.99 9999.99 2024-12-09 2099-12-31

See this db<>fiddle for a demo.

I have slightly corrected the description of the table. It’s more consistent with your text.
Mainly – set default value for column VALID_UNTIL.

create table ma_costs(
  ITEM_ID VARCHAR(255) NOT NULL ,
  COST1 FLOAT NOT NULL,
  COST2 FLOAT NOT NULL,
  PRICE1 FLOAT NOT NULL,
  PRICE2 FLOAT NOT NULL,
  VALID_FROM DATE NOT NULL , 
  VALID_UNTIL DATE default '2099-12-31'  NULL,
  PRIMARY KEY(item_id,valid_from)
);
create index ix_ma_costs_item_id_valid_from on ma_costs(item_id,valid_from);

Your trigger works, when you insert 1 row in query. Then there is 1 row with the value valid_until=’2099-12-31′. JOIN is correct

ON t.ITEM_ID= i.ITEM_ID
 AND t.VALID_UNTIL = '2099-12-31' AND t.VALID_FROM < i.VALID_FROM

When you insert batch, and default value for valid_until is ‘2099-12-31’ INNER JOIN in trigger can not work correctly. There only 1 row in t match to all rows in i.

See example:
For test. Insert 1 row without trigger. Default for valid_until is correct.

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008201, 4062.71, 4062.71, 5803.81, 6732.41, '2024-10-01');
select * from ma_costs;
ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2099-12-31

Your trigger:

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
    FROM MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
        AND t.VALID_UNTIL = '2099-12-31'
        AND t.VALID_FROM < i.VALID_FROM;
END;

Insert rows one by one (item_id=2008201).

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4062.7, 4062.7, 5803.85, 6732.47, '2024-12-01');
INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4119.57, 4119.57, 5885.09, 6826.7, '2024-12-02');
INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4150.85, 4150.85, 5929.78, 6878.54, '2024-12-06');

Output is correct

ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2024-12-01
2008201 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008201 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-06
2008201 4150.85 4150.85 5929.78 6878.54 2024-12-06 2099-12-31

Insert several rows simultaneously (item_id=2008209)

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008209, 4062.7, 4062.7, 5803.85, 6732.47, '2024-11-01'),
(2008209, 4119.57, 4119.57, 5885.09, 6826.7, '2024-11-02'),
(2008209, 4150.85, 4150.85, 5929.78, 6878.54, '2024-11-06');
ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2024-12-01
2008201 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008201 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-06
2008201 4150.85 4150.85 5929.78 6878.54 2024-12-06 2099-12-31
2008209 4062.7 4062.7 5803.85 6732.47 2024-11-01 2024-11-06
2008209 4119.57 4119.57 5885.09 6826.7 2024-11-02 2024-11-06
2008209 4150.85 4150.85 5929.78 6878.54 2024-11-06 2099-12-31

fiddle

My suggestion is

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    declare @nn bigint;
    set @nn=next value for sq_trigger_work_count; -- for test
    SET NOCOUNT ON;
    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
          -- log operation to column testValue
       ,t.testValue=concat('(',i.valid_from,'-',i.valid_until
                  ,':',t.valid_from,'-',t.valid_until
                  ,':',(select count(*) from ma_costs)
          ,')'   ) 
    FROM MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
      and t.valid_from=(select max(valid_from) from ma_costs t2 
                        where t2.item_id=i.item_id and  t2.valid_from<i.valid_from)

      ;
END;

Details see in example fiddle

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Trigger on insert for each new record

I have a table with this structure

ITEM_ID VARCHAR(255) NOT NULL PRIMARY KEY,
COST1 FLOAT NOT NULL,
COST2 FLOAT NOT NULL,
PRICE1 FLOAT NOT NULL,
PRICE2 FLOAT NOT NULL,
VALID_FROM DATE NOT NULL PRIMARY KEY,
VALID_UNTIL DATE NULL,

The default value for VALID_UNTIL is ‘2099-12-31’

I need to create a trigger in this table so that when I insert new records the most recent record in the table updates the value of VALID_UNTIL to be the same as the value of VALID_FROM of the record being inserted as long as ITEM_ID is the same. And when there is no record matching on the table I want it to just insert the new record.

And I want the trigger to apply for every new record individually from oldest to newest by the VALID_FROM column being inserted.

I already tried this query, but the trigger applies to all the records being inserted at the same time so the VALID_UNTIL result for every record is ‘2099-12-31’

CREATE TRIGGER trg_update_valid_until
ON cal.MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
    FROM cal.MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
        AND t.VALID_UNTIL = '2099-12-31'
        AND t.VALID_FROM < i.VALID_FROM;
END;

Here is some sample data as well

INSERT INTO cal.MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008209, 4062.7, 4062.7, 5803.85, 6732.47, '2024-12-01'),
(2008209, 4119.57, 4119.57, 5885.09, 6826.7, '2024-12-02'),
(2008209, 4150.85, 4150.85, 5929.78, 6878.54, '2024-12-06');

New contributor

Santiago C is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

10

For a more robust solution, don’t store VALID_UNTIL because VALID_FROM is enough. When you need to obtain the prices for a given date just use the following query:

select top 1 *
from MA_COSTS
where ITEM_ID = @ItemId
and VALID_FROM <= @DateOfInterest
order by VALID_FROM desc;

There is no advantage in storing VALID_UNTIL – it just makes things more complicated.

And ensure you change the datatype of your columns – DO NOT USE FLOAT to store money! Float is an inaccurate datatype intended for scientific data… you need a precise datatype, you don’t want to lose money due to the behaviour of float. Use something like decimal(18,2)

0

I like Dale K’s idea of eliminating the VALID_UNTIL column and using the CROSS APPLY (SELECT TOP 1 ...) pattern for looking up prices.

However, if that isn’t an option, the following should satisfy your needs.

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE tPrior
    SET VALID_UNTIL = i.VALID_FROM
    FROM inserted i
    CROSS APPLY (
        -- Locate immediately prior cost row for this item
        SELECT TOP 1 t.*
        FROM MA_COSTS t
        WHERE t.ITEM_ID = i.ITEM_ID
        AND t.VALID_FROM < i.VALID_FROM
        ORDER BY t.VALID_FROM DESC
    ) tPrior
    WHERE tPrior.VALID_UNTIL = '2099-12-31'
    --or perhaps: WHERE tPrior.VALID_UNTIL > i.VALID_FROM
END;

For each inserted row, the prior row is identified and updated as needed.

An index in MA_COSTS(ITEM_ID, VALID_FROM) is needed to support direct lookup of the related rows using an index seek. If (ITEM_ID, VALID_FROM) is the primary key, no separate index is needed.

If you might be inserting rows with VALID_FROM values in the middle of the existing range, a second update may be needed to set the VALID_UNTIL values for the newly added row(s).

...
    UPDATE tCurrent
    SET VALID_UNTIL = tNext.VALID_FROM
    FROM inserted i
    JOIN MA_COSTS tCurrent
        ON tCurrent.ITEM_ID = i.ITEM_ID
        AND tCurrent.VALID_FROM = i.VALID_FROM
    CROSS APPLY (
        -- Locate immediately following cost row for this item
        SELECT TOP 1 t.*
        FROM MA_COSTS t
        WHERE t.ITEM_ID = i.ITEM_ID
        AND t.VALID_FROM > i.VALID_FROM
        ORDER BY t.VALID_FROM
    ) tNext
    WHERE tCurrent.VALID_UNTIL > tNext.VALID_FROM

Note that the above does not handle updates or deletes that may require adjustments to other rows.

Sample results after multiple insert operations with rows presented in a mixed order:

ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008209 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008209 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-03
2008209 3333.33 3333.33 3333.33 3333.33 2024-12-03 2024-12-04
2008209 4444.44 4444.44 4444.44 4444.44 2024-12-04 2024-12-05
2008209 5555.55 5555.55 5555.55 5555.55 2024-12-05 2024-12-06
2008209 4150.85 4150.85 5929.78 6878.54 2024-12-06 2024-12-07
2008209 7777.77 7777.77 7777.77 7777.77 2024-12-07 2024-12-08
2008209 8888.88 8888.88 8888.88 8888.88 2024-12-08 2024-12-09
2008209 9999.99 9999.99 9999.99 9999.99 2024-12-09 2099-12-31

See this db<>fiddle for a demo.

I have slightly corrected the description of the table. It’s more consistent with your text.
Mainly – set default value for column VALID_UNTIL.

create table ma_costs(
  ITEM_ID VARCHAR(255) NOT NULL ,
  COST1 FLOAT NOT NULL,
  COST2 FLOAT NOT NULL,
  PRICE1 FLOAT NOT NULL,
  PRICE2 FLOAT NOT NULL,
  VALID_FROM DATE NOT NULL , 
  VALID_UNTIL DATE default '2099-12-31'  NULL,
  PRIMARY KEY(item_id,valid_from)
);
create index ix_ma_costs_item_id_valid_from on ma_costs(item_id,valid_from);

Your trigger works, when you insert 1 row in query. Then there is 1 row with the value valid_until=’2099-12-31′. JOIN is correct

ON t.ITEM_ID= i.ITEM_ID
 AND t.VALID_UNTIL = '2099-12-31' AND t.VALID_FROM < i.VALID_FROM

When you insert batch, and default value for valid_until is ‘2099-12-31’ INNER JOIN in trigger can not work correctly. There only 1 row in t match to all rows in i.

See example:
For test. Insert 1 row without trigger. Default for valid_until is correct.

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008201, 4062.71, 4062.71, 5803.81, 6732.41, '2024-10-01');
select * from ma_costs;
ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2099-12-31

Your trigger:

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
    FROM MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
        AND t.VALID_UNTIL = '2099-12-31'
        AND t.VALID_FROM < i.VALID_FROM;
END;

Insert rows one by one (item_id=2008201).

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4062.7, 4062.7, 5803.85, 6732.47, '2024-12-01');
INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4119.57, 4119.57, 5885.09, 6826.7, '2024-12-02');
INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4150.85, 4150.85, 5929.78, 6878.54, '2024-12-06');

Output is correct

ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2024-12-01
2008201 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008201 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-06
2008201 4150.85 4150.85 5929.78 6878.54 2024-12-06 2099-12-31

Insert several rows simultaneously (item_id=2008209)

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008209, 4062.7, 4062.7, 5803.85, 6732.47, '2024-11-01'),
(2008209, 4119.57, 4119.57, 5885.09, 6826.7, '2024-11-02'),
(2008209, 4150.85, 4150.85, 5929.78, 6878.54, '2024-11-06');
ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2024-12-01
2008201 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008201 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-06
2008201 4150.85 4150.85 5929.78 6878.54 2024-12-06 2099-12-31
2008209 4062.7 4062.7 5803.85 6732.47 2024-11-01 2024-11-06
2008209 4119.57 4119.57 5885.09 6826.7 2024-11-02 2024-11-06
2008209 4150.85 4150.85 5929.78 6878.54 2024-11-06 2099-12-31

fiddle

My suggestion is

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    declare @nn bigint;
    set @nn=next value for sq_trigger_work_count; -- for test
    SET NOCOUNT ON;
    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
          -- log operation to column testValue
       ,t.testValue=concat('(',i.valid_from,'-',i.valid_until
                  ,':',t.valid_from,'-',t.valid_until
                  ,':',(select count(*) from ma_costs)
          ,')'   ) 
    FROM MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
      and t.valid_from=(select max(valid_from) from ma_costs t2 
                        where t2.item_id=i.item_id and  t2.valid_from<i.valid_from)

      ;
END;

Details see in example fiddle

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Trigger on insert for each new record

I have a table with this structure

ITEM_ID VARCHAR(255) NOT NULL PRIMARY KEY,
COST1 FLOAT NOT NULL,
COST2 FLOAT NOT NULL,
PRICE1 FLOAT NOT NULL,
PRICE2 FLOAT NOT NULL,
VALID_FROM DATE NOT NULL PRIMARY KEY,
VALID_UNTIL DATE NULL,

The default value for VALID_UNTIL is ‘2099-12-31’

I need to create a trigger in this table so that when I insert new records the most recent record in the table updates the value of VALID_UNTIL to be the same as the value of VALID_FROM of the record being inserted as long as ITEM_ID is the same. And when there is no record matching on the table I want it to just insert the new record.

And I want the trigger to apply for every new record individually from oldest to newest by the VALID_FROM column being inserted.

I already tried this query, but the trigger applies to all the records being inserted at the same time so the VALID_UNTIL result for every record is ‘2099-12-31’

CREATE TRIGGER trg_update_valid_until
ON cal.MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
    FROM cal.MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
        AND t.VALID_UNTIL = '2099-12-31'
        AND t.VALID_FROM < i.VALID_FROM;
END;

Here is some sample data as well

INSERT INTO cal.MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008209, 4062.7, 4062.7, 5803.85, 6732.47, '2024-12-01'),
(2008209, 4119.57, 4119.57, 5885.09, 6826.7, '2024-12-02'),
(2008209, 4150.85, 4150.85, 5929.78, 6878.54, '2024-12-06');

New contributor

Santiago C is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

10

For a more robust solution, don’t store VALID_UNTIL because VALID_FROM is enough. When you need to obtain the prices for a given date just use the following query:

select top 1 *
from MA_COSTS
where ITEM_ID = @ItemId
and VALID_FROM <= @DateOfInterest
order by VALID_FROM desc;

There is no advantage in storing VALID_UNTIL – it just makes things more complicated.

And ensure you change the datatype of your columns – DO NOT USE FLOAT to store money! Float is an inaccurate datatype intended for scientific data… you need a precise datatype, you don’t want to lose money due to the behaviour of float. Use something like decimal(18,2)

0

I like Dale K’s idea of eliminating the VALID_UNTIL column and using the CROSS APPLY (SELECT TOP 1 ...) pattern for looking up prices.

However, if that isn’t an option, the following should satisfy your needs.

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE tPrior
    SET VALID_UNTIL = i.VALID_FROM
    FROM inserted i
    CROSS APPLY (
        -- Locate immediately prior cost row for this item
        SELECT TOP 1 t.*
        FROM MA_COSTS t
        WHERE t.ITEM_ID = i.ITEM_ID
        AND t.VALID_FROM < i.VALID_FROM
        ORDER BY t.VALID_FROM DESC
    ) tPrior
    WHERE tPrior.VALID_UNTIL = '2099-12-31'
    --or perhaps: WHERE tPrior.VALID_UNTIL > i.VALID_FROM
END;

For each inserted row, the prior row is identified and updated as needed.

An index in MA_COSTS(ITEM_ID, VALID_FROM) is needed to support direct lookup of the related rows using an index seek. If (ITEM_ID, VALID_FROM) is the primary key, no separate index is needed.

If you might be inserting rows with VALID_FROM values in the middle of the existing range, a second update may be needed to set the VALID_UNTIL values for the newly added row(s).

...
    UPDATE tCurrent
    SET VALID_UNTIL = tNext.VALID_FROM
    FROM inserted i
    JOIN MA_COSTS tCurrent
        ON tCurrent.ITEM_ID = i.ITEM_ID
        AND tCurrent.VALID_FROM = i.VALID_FROM
    CROSS APPLY (
        -- Locate immediately following cost row for this item
        SELECT TOP 1 t.*
        FROM MA_COSTS t
        WHERE t.ITEM_ID = i.ITEM_ID
        AND t.VALID_FROM > i.VALID_FROM
        ORDER BY t.VALID_FROM
    ) tNext
    WHERE tCurrent.VALID_UNTIL > tNext.VALID_FROM

Note that the above does not handle updates or deletes that may require adjustments to other rows.

Sample results after multiple insert operations with rows presented in a mixed order:

ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008209 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008209 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-03
2008209 3333.33 3333.33 3333.33 3333.33 2024-12-03 2024-12-04
2008209 4444.44 4444.44 4444.44 4444.44 2024-12-04 2024-12-05
2008209 5555.55 5555.55 5555.55 5555.55 2024-12-05 2024-12-06
2008209 4150.85 4150.85 5929.78 6878.54 2024-12-06 2024-12-07
2008209 7777.77 7777.77 7777.77 7777.77 2024-12-07 2024-12-08
2008209 8888.88 8888.88 8888.88 8888.88 2024-12-08 2024-12-09
2008209 9999.99 9999.99 9999.99 9999.99 2024-12-09 2099-12-31

See this db<>fiddle for a demo.

I have slightly corrected the description of the table. It’s more consistent with your text.
Mainly – set default value for column VALID_UNTIL.

create table ma_costs(
  ITEM_ID VARCHAR(255) NOT NULL ,
  COST1 FLOAT NOT NULL,
  COST2 FLOAT NOT NULL,
  PRICE1 FLOAT NOT NULL,
  PRICE2 FLOAT NOT NULL,
  VALID_FROM DATE NOT NULL , 
  VALID_UNTIL DATE default '2099-12-31'  NULL,
  PRIMARY KEY(item_id,valid_from)
);
create index ix_ma_costs_item_id_valid_from on ma_costs(item_id,valid_from);

Your trigger works, when you insert 1 row in query. Then there is 1 row with the value valid_until=’2099-12-31′. JOIN is correct

ON t.ITEM_ID= i.ITEM_ID
 AND t.VALID_UNTIL = '2099-12-31' AND t.VALID_FROM < i.VALID_FROM

When you insert batch, and default value for valid_until is ‘2099-12-31’ INNER JOIN in trigger can not work correctly. There only 1 row in t match to all rows in i.

See example:
For test. Insert 1 row without trigger. Default for valid_until is correct.

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008201, 4062.71, 4062.71, 5803.81, 6732.41, '2024-10-01');
select * from ma_costs;
ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2099-12-31

Your trigger:

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
    FROM MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
        AND t.VALID_UNTIL = '2099-12-31'
        AND t.VALID_FROM < i.VALID_FROM;
END;

Insert rows one by one (item_id=2008201).

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4062.7, 4062.7, 5803.85, 6732.47, '2024-12-01');
INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4119.57, 4119.57, 5885.09, 6826.7, '2024-12-02');
INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES (2008201, 4150.85, 4150.85, 5929.78, 6878.54, '2024-12-06');

Output is correct

ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2024-12-01
2008201 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008201 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-06
2008201 4150.85 4150.85 5929.78 6878.54 2024-12-06 2099-12-31

Insert several rows simultaneously (item_id=2008209)

INSERT INTO MA_COSTS (ITEM_ID, COST1, COST2, PRICE1, PRICE2, VALID_FROM)
VALUES
(2008209, 4062.7, 4062.7, 5803.85, 6732.47, '2024-11-01'),
(2008209, 4119.57, 4119.57, 5885.09, 6826.7, '2024-11-02'),
(2008209, 4150.85, 4150.85, 5929.78, 6878.54, '2024-11-06');
ITEM_ID COST1 COST2 PRICE1 PRICE2 VALID_FROM VALID_UNTIL
2008201 4062.71 4062.71 5803.81 6732.41 2024-10-01 2024-12-01
2008201 4062.7 4062.7 5803.85 6732.47 2024-12-01 2024-12-02
2008201 4119.57 4119.57 5885.09 6826.7 2024-12-02 2024-12-06
2008201 4150.85 4150.85 5929.78 6878.54 2024-12-06 2099-12-31
2008209 4062.7 4062.7 5803.85 6732.47 2024-11-01 2024-11-06
2008209 4119.57 4119.57 5885.09 6826.7 2024-11-02 2024-11-06
2008209 4150.85 4150.85 5929.78 6878.54 2024-11-06 2099-12-31

fiddle

My suggestion is

CREATE TRIGGER trg_update_valid_until
ON MA_COSTS
AFTER INSERT
AS
BEGIN
    declare @nn bigint;
    set @nn=next value for sq_trigger_work_count; -- for test
    SET NOCOUNT ON;
    UPDATE t
    SET t.VALID_UNTIL = i.VALID_FROM
          -- log operation to column testValue
       ,t.testValue=concat('(',i.valid_from,'-',i.valid_until
                  ,':',t.valid_from,'-',t.valid_until
                  ,':',(select count(*) from ma_costs)
          ,')'   ) 
    FROM MA_COSTS t
    INNER JOIN inserted i
        ON t.ITEM_ID= i.ITEM_ID
      and t.valid_from=(select max(valid_from) from ma_costs t2 
                        where t2.item_id=i.item_id and  t2.valid_from<i.valid_from)

      ;
END;

Details see in example fiddle

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật