0

我有一个计算机表,其中包含“购买日期”和“保修到期”等列。我希望每台计算机(行)在“购买日期”中取其日期值加上 4 年,并将结果放在“保修到期”列中。我还希望在我创建新计算机并尽可能输入其购买日期时自动发生这种情况。

谢谢

4

1 回答 1

6

删除列并计算它:

ALTER TABLE dbo.TableName DROP COLUMN WarrantyExpires;

ALTER TABLE dbo.TableName ADD WarrantyExpires
  AS CONVERT(DATE, DATEADD(YEAR, 4, DatePurchased));

或者更好的是,甚至不要存储这个。由于每一行都是相同的(假设您没有不是 4 年的保修),因此只需在运行时执行计算。

如果每一行都不相同,或者如果客户可以(现在或以后)延长他们的保修期,那么计算列不是要走的路。反而:

ALTER TABLE dbo.TableName ADD WarrantyExpires DATE;

然后一个INSTEAD OF触发器可能会根据插入提供的值(您将使用它来覆盖)或从购买日期起四年(如果没有提供到期日期的值)来填充它。所以:

CREATE TRIGGER dbo.FixWarrantyDate
ON dbo.TableName
INSTEAD OF INSERT
AS
BEGIN
  SET NOCOUNT ON;

  INSERT dbo.TableName(OrderID, /* other cols, */ DatePurchased, WarrantyExpires)
    SELECT OrderID, /* other cols, */ COALESCE(DatePurchased,GETDATE()),
      COALESCE(WarrantyExpires,DATEADD(YEAR,4,COALESCE(DatePurchased,GETDATE())))
    FROM inserted;
END
GO

所以现在你的基本插入在默认情况下可能看起来像这样:

INSERT dbo.TableName(OrderID, DatePurchased, WarrantyExpires)
  SELECT 1, GETDATE(), NULL;

-- or

INSERT dbo.TableName(OrderID, DatePurchased)
  SELECT 2, GETDATE();

-- or even:

INSERT dbo.TableName(OrderID) SELECT 3;

如果有人购买了延长保修,您可以覆盖它(或稍后手动更新):

INSERT dbo.TableName(OrderID, DatePurchased, WarrantyExpires)
  SELECT 4, GETDATE(), DATEADD(YEAR, 5, GETDATE());

这四次插入后表中的结果数据:

OrderID   DatePurchased   WarrantyExpires
-------   -------------   ---------------
1         2013-10-25      2017-10-25
2         2013-10-25      2017-10-25
3         2013-10-25      2017-10-25
4         2013-10-25      2018-10-25

现在我觉得我也应该解释为什么我更喜欢INSTEAD OF触发器。虽然它们确实需要您重新编写插入语句,而触发器之后不需要,但它们增加了以下好处:

  • 即使在您处理完业务逻辑之后,您仍然可以在一个语句中执行插入(并更新通常由 after 触发器处理的内容)。这对日志更友好。

  • 如果您的触发器中有可能回滚事务的业务逻辑,那么最好在INSTEAD OF触发器中这样做。而不是写入行,影响日志,可能导致页面拆分,然后删除行,影响日志,并添加需要稍后清理的幻影行,您只需退出而不执行插入。

于 2013-10-25T14:39:53.543 回答