2014-10-09 20 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