У вас не может быть вычисляемого столбца на основе данных за пределами текущей обновляемой строки. Лучшее, что вы можете сделать, чтобы сделать это автоматическим, — это создать афтер-триггер, который запрашивает всю таблицу, чтобы найти следующее значение для кода продукта. Но для того, чтобы это работало, вам придется использовать эксклюзивную блокировку таблицы, которая полностью уничтожит параллелизм, так что это не очень хорошая идея.
Я также не рекомендую использовать представление, потому что ему придется вычислять ProductCode каждый раз, когда вы читаете таблицу. Это также было бы огромным убийцей производительности. Если вы не сохраните значение в базе данных, чтобы его больше никогда не трогали, ваши коды продуктов могут быть подвержены ложным изменениям (например, в случае удаления ошибочно введенного и никогда не используемого продукта).
Вот что я рекомендую вместо этого. Создайте новую таблицу:
dbo.SellerProductCode
SellerID LastProductCode
-------- ---------------
1 3
2 1
Эта таблица надежно записывает последний использованный код продукта для каждого продавца. На INSERT
в вашу таблицу Product
триггер обновит LastProductCode
в этой таблице соответствующим образом для всех затронутых SellerID
, а затем обновит все вновь вставленные строки в таблице Product
соответствующими значениями. Это может выглядеть примерно так, как показано ниже.
Посмотрите, как этот триггер работает в скрипте Sql
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 для рабочего, протестированного кода, демонстрирующего технику. Теперь у вас есть настоящие коды продуктов, которые не нужно менять и которые будут надежными.
person
ErikE
schedule
20.02.2013
persisted
). - person Tim Lehner   schedule 20.02.2013