您需要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