У вас нет расчетного столбца на основе данных за пределами текущей строки, которая обновляется. Лучшее, что вы можете сделать, чтобы сделать это автоматическое, - создать после триггер, который запрашивает всю таблицу, чтобы найти следующее значение для кода продукта. Но для выполнения этой работы вам придется использовать эксклюзивную блокировку таблицы, которая полностью уничтожит параллелизм, поэтому это не очень хорошая идея.
Я также не рекомендую использовать представление, потому что он должен будет вычислять 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'). –
@TimLehner Можете ли вы предоставить образец? Я все еще хотел бы знать, возможно ли это использование вычисляемых столбцов? –