在SQL Server中使用ROW_NUMBER()获取上一条记录的值

在SQL Server中使用ROW_NUMBER()获取上一条记录的值,sql,sql-server,row-number,Sql,Sql Server,Row Number,希望这对于那些在SQL Server方面更有经验的人来说足够容易 我有一个客户贷款活动数据表,每当他们的帐户发生操作时,该表都会更新。例如,如果他们的限额增加,将使用他们的新限额创建一个新记录。我希望能够创建一个他们的活动列表,其中活动量是他们的新限额减去他们以前的限额 目前我有以下内容,但我正在努力找出如何访问以前的记录 SELECT CUSTOMER ,LEDGER ,ACCOUNT ,H.AMOUNT - COALESCE(X.AMOUNT, 0) F

希望这对于那些在SQL Server方面更有经验的人来说足够容易

我有一个客户贷款活动数据表,每当他们的帐户发生操作时,该表都会更新。例如,如果他们的限额增加,将使用他们的新限额创建一个新记录。我希望能够创建一个他们的活动列表,其中活动量是他们的新限额减去他们以前的限额

目前我有以下内容,但我正在努力找出如何访问以前的记录

SELECT   
    CUSTOMER
    ,LEDGER
    ,ACCOUNT
    ,H.AMOUNT - COALESCE(X.AMOUNT, 0)
FROM 
    dbo.ACTIVITY H WITH (NOLOCK)
LEFT OUTER JOIN 
    (SELECT  
        CUSTOMER
        ,LEDGER
        ,ACCOUNT
        ,ACTIVITY_DATE
        ,AMOUNT
        ,ROW_NUMBER() OVER (PARTITION BY CUSTOMER, LEDGER, ACCOUNT ORDER BY ACTIVITY_DATE ASC) AS ROW_NUMBER
     FROM 
         dbo.ACTIVITY WITH (NOLOCK)) X ON H.CUSTOMER = X.CUSTOMER
                                          AND H.LEDGER = X.LEDGER
                                          AND H.ACCOUNT = X.ACCOUNT
因此,基本上我只想减去
x.amount
,如果它是以前的记录,但我不知道在什么时候发生的,我不知道该怎么做

我以为
行号()
会对我有所帮助,但我还是有点困惑

希望你们很快收到你们的来信:)


干杯

这里的查询只会通过
dbo.Activity
一次

    SELECT H.CUSTOMER
          ,H.LEDGER
          ,H.ACCOUNT
          ,MAX(H.ACTIVITY_DATE) ACTIVITY_DATE
          ,SUM(CASE X.I WHEN 1 THEN AMOUNT ELSE -AMOUNT END) AMOUNT
      FROM (SELECT CUSTOMER
                  ,LEDGER
                  ,ACCOUNT
                  ,ACTIVITY_DATE
                  ,AMOUNT
                  ,ROW_NUMBER() OVER (PARTITION BY CUSTOMER, LEDGER, ACCOUNT ORDER BY ACTIVITY_DATE DESC) AS ROW_NUMBER
             FROM dbo.ACTIVITY WITH (NOLOCK)
           ) H
CROSS JOIN (select 1 union all select 2) X(I)
     WHERE ROW_NUMBER - X.I >= 0
  GROUP BY H.CUSTOMER
          ,H.LEDGER
          ,H.ACCOUNT
          ,ROW_NUMBER - X.I;
这是我用来测试的一些数据的DDL/DML

CREATE TABLE dbo.ACTIVITY(CUSTOMER int, LEDGER int, ACCOUNT int, ACTIVITY_DATE datetime, AMOUNT int)
INSERT dbo.ACTIVITY select
    1,2,3,GETDATE(),123 union all select
    1,2,3,GETDATE()-1,16 union all select
    1,2,3,GETDATE()-2,12 union all select
    1,2,3,GETDATE()-3,1 union all select
    4,5,6,GETDATE(),1000 union all select
    4,5,6,GETDATE()-6,123 union all select
    7,7,7,GETDATE(),99;

选择 更传统的方法是使用子查询获取前一行:

  SELECT CUSTOMER, LEDGER, ACCOUNT, ACTIVITY_DATE,
         AMOUNT - ISNULL((SELECT TOP(1) I.AMOUNT
                            FROM dbo.ACTIVITY I
                           WHERE I.CUSTOMER = O.CUSTOMER
                             AND I.LEDGER = O.LEDGER
                             AND I.ACCOUNT = O.ACCOUNT
                             AND I.ACTIVITY_DATE < O.ACTIVITY_DATE
                        ORDER BY I.ACTIVITY_DATE DESC), 0) AMOUNT
    FROM dbo.ACTIVITY O
ORDER BY CUSTOMER, LEDGER, ACCOUNT, ACTIVITY_DATE;

哪个版本的SQL Server?2012有一个
LAG()
函数。谢谢Richard。我会试试的。嗨,Richard,你更传统的方法是我最后自己制定并采用的方法。我试图回答我自己的问题,但显然不能,因为我是个新手。谢谢你的帮助……)请记住勾选答案作为解决方案。顺便说一句,第一个解决方案虽然更难理解,但性能会更好
   SELECT A.CUSTOMER, A.LEDGER, A.ACCOUNT, A.ACTIVITY_DATE, 
          A.AMOUNT - ISNULL(B.AMOUNT,0) AMOUNT
     FROM (SELECT *, RN=ROW_NUMBER() OVER (partition by CUSTOMER, LEDGER, ACCOUNT
                                          order by ACTIVITY_DATE ASC)
            FROM dbo.ACTIVITY) A
LEFT JOIN (SELECT *, RN=ROW_NUMBER() OVER (partition by CUSTOMER, LEDGER, ACCOUNT
                                          order by ACTIVITY_DATE ASC)
            FROM dbo.ACTIVITY) B ON A.CUSTOMER = B.CUSTOMER
                              AND A.LEDGER = B.LEDGER
                              AND A.ACCOUNT = B.ACCOUNT
                              AND B.RN = A.RN-1 -- prior record
ORDER BY A.CUSTOMER, A.LEDGER, A.ACCOUNT, A.ACTIVITY_DATE;