2014-10-09 58 views
2

我有一个Sales表数据如下:SQL服务器:如何创建序列号列

| SalesId | CustomerId | Amount | 
|---------|------------|--------| 
| 1  | 1   | 100 | 
| 2  | 2   | 75  | 
| 3  | 1   | 30  | 
| 4  | 3   | 49  | 
| 5  | 1   | 93  | 

我想插入一列到这个表格告诉我们的客户取得的次数一项采购。所以它会是这样:

| SalesId | CustomerId | Amount | SalesNum | 
|---------|------------|--------|----------| 
| 1  | 1   | 100 | 1  | 
| 2  | 2   | 75  | 1  | 
| 3  | 1   | 30  | 2  | 
| 4  | 3   | 49  | 1  | 
| 5  | 1   | 93  | 3  | 

所以,我可以看到,在salesId = 5,这是对客户ID = 1的第3交易我怎么能写这样的查询,插入/更新这些列?我在MS SQL上,但我也对MYSQL解决方案感兴趣,因为我需要在将来这样做。

谢谢。

ps。表格格式的道歉。无法弄清楚如何很好地格式化它。

回答

1

您需要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相同,则需要使用RANKDENSE_RANKDENSE_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

试试这个 -

SELECT SalesId, CustomerId, Amount, 
SalesNum = ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY SalesId) 
FROM YOURTABLE 
+0

+1更快,但不会在MySQL运行。 – 2014-10-09 10:31:14

+0

@JoachimIsaksson:OP没有提及在MySQL中运行它... – 2014-10-09 10:36:04

+0

引用这个问题; “我使用MS SQL,但我也对MYSQL解决方案感兴趣,因为我将来需要在那里做这件事。” – 2014-10-09 10:36:43

2

使用子查询,

Select *, (Select count(customerid) 
       from ##tmp t 
       where t.salesid <= s.salesid 
       and  t.customerid = s.customerid) 
from ##tmp s 
+0

+1较慢,但应该在SQL Server和MySQL上运行。 – 2014-10-09 10:31:32