根据当前正在更新的行以外的数据,您不能拥有计算列。您可以做的最好的做法是自动创建一个后触发器,查询整个表以查找产品代码的下一个值。但为了完成这项工作,你必须使用独占表锁,这将完全破坏并发性,所以这不是一个好主意。
我也不建议使用视图,因为每次读取表时都必须计算ProductCode。这也是一个巨大的性能杀手。通过不再将数据保存在数据库中,永远不会再次触及,您的产品代码将受到虚假更改(例如可能会删除错误输入和未使用的产品)。
这是我推荐的。创建一个新表格:
dbo。SellerProductCode
SellerID LastProductCode
-------- ---------------
1 3
2 1
这台可靠地记录了每个卖家上次使用的产品代码。在INSERT
到Product
表中,触发器将适当地更新此表中LastProductCode
对所有受影响的SellerID
s,然后使用适当的值更新Product
表中的所有新插入的行。它可能看起来像下面那样。
See this trigger working in a 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)。
请做see the Sql Fiddle工作,测试代码演示技术。现在您有real产品代码,没有任何理由可以更改并且可靠。
我会建议使用视图来做这种计算。如果选择性能是最重要的因素(我看你使用'persisted'),这个视图甚至可以被索引。 – 2013-02-19 21:15:13
@TimLehner你能提供样品吗?我仍然想知道是否可以使用Computed列? – 2013-02-19 21:19:40