SQL Server:如何创建序列号列

时间:2014-10-09 10:19:12

标签: sql-server

我有一个包含以下数据的Sales表:

| 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中,这是customerId = 1的第3个事务。如何编写这样的查询来插入/更新这样的列?我在使用MS SQL,但我也对MYSQL解决方案感兴趣,如果我将来需要这样做的话。

谢谢。

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

3 个答案:

答案 0 :(得分:2)

使用子查询,

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

答案 1 :(得分:1)

试试这个 -

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

答案 2 :(得分: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,那么在ROW_NUMBER()中没有任何其他订购条件的情况下,它们将没有相同的SalesNum功能他们将被随机分类。如果您希望具有相同金额的销售额具有相同的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