2013-02-19 125 views
0

我有1 SellerId用於計算列特定需要叫產品代碼計算列表達式

ProductId | SellerId | ProductCode 
1   1   000001 
2   1   000002 
3   2   000001  
4   1   000003 

產品編號是身份,增量是一個外鍵。

所以我的計算專欄ProductCode必須看賣家有多少產品,並且格式爲000000.這裏的問題是如何知道要查找哪些賣家產品?

我已經寫了有一個TSQL不看多少產品沒有賣家有

ALTER TABLE dbo.Product 
ADD ProductCode AS RIGHT('000000' + CAST(ProductId AS VARCHAR(6)) , 6) PERSISTED 
+1

我會建議使用視圖來做這種計算。如果選擇性能是最重要的因素(我看你使用'persisted'),這個視圖甚至可以被索引。 – 2013-02-19 21:15:13

+0

@TimLehner你能提供樣品嗎?我仍然想知道是否可以使用Computed列? – 2013-02-19 21:19:40

回答

2

根據當前正在更新的行以外的數據,您不能擁有計算列。您可以做的最好的做法是自動創建一個後觸發器,查詢整個表以查找產品代碼的下一個值。但爲了完成這項工作,你必須使用獨佔表鎖,這將完全破壞併發性,所以這不是一個好主意。

我也不建議使用視圖,因爲每次讀取表時都必須計算ProductCode。這也是一個巨大的性能殺手。通過不再將數據保存在數據庫中,永遠不會再次觸及,您的產品代碼將受到虛假更改(例如可能會刪除錯誤輸入和未使用的產品)。

這是我推薦的。創建一個新表格:

dbo。SellerProductCode

SellerID LastProductCode 
-------- --------------- 
    1  3 
    2  1 

這臺可靠地記錄了每個賣家上次使用的產品代碼。在INSERTProduct表中,觸發器將適當地更新此表中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產品代碼,沒有任何理由可以更改並且可靠。

+0

感謝您的詳細解釋。 – 2013-02-20 03:11:24

0

我通常會建議使用視圖做這類型的計算。如果選擇性能是最重要的因素(我看你使用的是persisted),該視圖甚至可以被索引。

在計算列中不能有子查詢,這實際上意味着您只能訪問當前行中的數據。獲得此計數的唯一方法是使用user-defined function in your computed column或觸發器來更新非計算列。

視圖看起來可能像下面這樣:

create view ProductCodes as 
select p.ProductId, p.SellerId, 
    (
      select right('000000' + cast(count(*) as varchar(6)), 6) 
      from Product 
      where SellerID = p.SellerID 
       and ProductID <= p.ProductID 
    ) as ProductCode 
from Product p 

一個重要的提醒到你的產品的編號方案,併爲雙方的觀點和UDF選項的垮臺,是我們在行的總數依賴用較低的ProductId。這意味着如果在序列中間插入產品,實際上將更高的ProductId更改現有產品的ProductCodes。在這一點上,你必須:(?還是半信半疑,但也許CREATEDATE)

  • 保證產品編號的順序(單獨的身份並沒有這樣做)
  • 依靠具有保證序列的不同列
  • 使用觸發器來獲得插入計數,然後永遠不會改變。