您不能拥有基于正在更新的当前行之外的数据的计算列。您可以做的最好的事情是创建一个后触发器来查询整个表以查找产品代码的下一个值。但是为了完成这项工作,您必须使用排他表锁,这将彻底破坏并发性,所以这不是一个好主意。
我也不建议使用视图,因为每次阅读表格时它都必须计算 ProductCode。这也将是一个巨大的性能杀手。通过不将值保存在数据库中以使其不再被触摸,您的产品代码将受到虚假更改(例如可能删除错误输入且从未使用过的产品的情况)。
这是我推荐的。创建一个新表:
dbo.SellerProductCode
SellerID LastProductCode
-------- ---------------
1 3
2 1
该表可靠地记录了每个卖家最后使用的产品代码。在INSERT
您的Product
表上,触发器将LastProductCode
针对所有受影响SellerID
的 s 适当地更新此表中的 ,然后Product
使用适当的值更新表中所有新插入的行。它可能看起来像下面这样。
查看此触发器在 Sql Fiddle 中工作
CREATE TRIGGER TR_Product_I ON dbo.Product FOR INSERT
AS
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @LastProductCode TABLE (
SellerID int NOT NULL PRIMARY KEY CLUSTERED,
LastProductCode int NOT NULL
);
WITH ItemCounts AS (
SELECT
I.SellerID,
ItemCount = Count(*)
FROM
Inserted I
GROUP BY
I.SellerID
)
MERGE dbo.SellerProductCode C
USING ItemCounts I
ON C.SellerID = I.SellerID
WHEN NOT MATCHED BY TARGET THEN
INSERT (SellerID, LastProductCode)
VALUES (I.SellerID, I.ItemCount)
WHEN MATCHED THEN
UPDATE SET C.LastProductCode = C.LastProductCode + I.ItemCount
OUTPUT
Inserted.SellerID,
Inserted.LastProductCode
INTO @LastProductCode;
WITH P AS (
SELECT
NewProductCode =
L.LastProductCode + 1
- Row_Number() OVER (PARTITION BY I.SellerID ORDER BY P.ProductID DESC),
P.*
FROM
Inserted I
INNER JOIN dbo.Product P
ON I.ProductID = P.ProductID
INNER JOIN @LastProductCode L
ON P.SellerID = L.SellerID
)
UPDATE P
SET P.ProductCode = Right('00000' + Convert(varchar(6), P.NewProductCode), 6);
请注意,即使插入了多行,此触发器也有效。也不需要预加载SellerProductCode
表格,新卖家会自动添加。这将处理并发问题。如果遇到并发问题,可以添加适当的锁定提示而不会产生有害影响,因为表将保持非常小并且可以使用 ROWLOCK(除了需要范围锁定的 INSERT)。
请查看 Sql Fiddle以了解演示该技术的工作、测试代码。现在您拥有无需更改且可靠的真实产品代码。