您需要ROW_NUMBER()分配一個序列號。我強烈反對,雖然存儲這個值,因爲您將需要每次更新後重新計算它,相反,如果你經常需要它,你可能最好是去創建一個視圖:
CREATE VIEW dbo.SalesWithRank
AS
SELECT SalesID,
CustomerID,
Amount,
SalesNum = ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY SalesID)
FROM Sales;
GO
SQL Server Example on SQL Fiddle
ROW_NUMBER()
不會在同一組中分配重複項,例如如果您根據Amount
分配行,並且同一個客戶的兩個銷售額均爲100,則它們將不具有相同的SalesNum,因爲ROW_NUMBER()
函數中沒有任何其他訂購條件時,它們將隨機排序。如果您希望銷售金額與SalesNum
相同,則需要使用RANK
或DENSE_RANK
。 DENSE_RANK
將在序列中沒有空位,例如1, 1, 2, 2, 3
,而RANK
將從相應位置開始,例如, 1, 1, 3, 3, 5
。
如果你必須這樣做,作爲一個更新,那麼你可以使用:
WITH CTE AS
( SELECT SalesID,
CustomerID,
Amount,
SalesNum,
NewSalesNum = ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY SalesID)
FROM Sales
)
UPDATE CTE
SET SalesNum = NewSalesNum;
SQL Server Update Example on SQL Fiddle
MySQL沒有排名的功能,所以你需要使用局部變量以實現等級跟蹤前一行的價值。這不是在視圖中不允許這樣你只需要重複此邏輯,無論你需要的行號:
SELECT s.SalesID,
s.Amount,
@r:= CASE WHEN @c = s.CustomerID THEN @r + 1 ELSE 1 END AS SalesNum,
@c:= CustomerID AS CustomerID
FROM Sales AS s
CROSS JOIN (SELECT @c:= 0, @r:= 0) AS var
ORDER BY s.CustomerID, s.SalesID;
順序通過是至關重要的位置,這意味着以命令不影響結果的排名,你需要使用子查詢:
SELECT SalesID,
Amount,
CustomerID,
SalesNum
FROM ( SELECT s.SalesID,
s.Amount,
@r:= CASE WHEN @c = s.CustomerID THEN @r + 1 ELSE 1 END AS SalesNum,
@c:= CustomerID AS CustomerID
FROM Sales AS s
CROSS JOIN (SELECT @c:= 0, @r:= 0) AS var
ORDER BY s.CustomerID, s.SalesID
) AS s
ORDER BY s.SalesID;
MySQL Example on SQL Fiddle
再次,我建議對存儲的價值,但如果你必須在MySQL中,你可以使用:
UPDATE Sales
INNER JOIN
( SELECT s.SalesID,
@r:= CASE WHEN @c = s.CustomerID THEN @r + 1 ELSE 1 END AS NewSalesNum,
@c:= CustomerID AS CustomerID
FROM Sales AS s
CROSS JOIN (SELECT @c:= 0, @r:= 0) AS var
ORDER BY s.CustomerID, s.SalesID
) AS s2
ON Sales.SalesID = s2.SalesID
SET SalesNum = s2.NewSalesNum;
MySQL Update Example on SQL Fiddle
+1更快,但不會在MySQL運行。 – 2014-10-09 10:31:14
@JoachimIsaksson:OP沒有提及在MySQL中運行它... – 2014-10-09 10:36:04
引用這個問題; 「我使用MS SQL,但我也對MYSQL解決方案感興趣,因爲我將來需要在那裏做這件事。」 – 2014-10-09 10:36:43