在联接中重复上一行的值

时间:2019-01-20 22:31:08

标签: tsql sql-server-2008

我有一张桌子,包括帐户及其余额。我想报告每一天的余额,而缺少的日子要报告最后一天。 表帐户:

AccountName    Date         Balance
thomas         2008-10-09   1000
thomas         2008-10-20   5000
david          2008-02-18   2000
david          2008-03-10   200000

假设我们想要2018-10年度的报告,我需要获得类似的信息

thomas         2008-10-01   0
...
thomas         2008-10-09   1000
thomas         2008-10-10   1000
...
thomas         2008-10-20   5000
...
thomas         2008-10-31   5000

我走了这么远:

DECLARE @StartDate datetime = '2008/10/9';
DECLARE @EndDate   datetime = '2008/10/20';
WITH theDates AS
     (
        SELECT @StartDate as theDate
            UNION ALL
        SELECT DATEADD(day, 1, theDate)
            FROM theDates
        WHERE DATEADD(day, 1, theDate) <= @EndDate
     )
select * from accounts a
right outer join thedates d on a.date=d.theDate
order by thedate

结果:

AccountNo   Date       Balance  theDate
----------- ---------- -------- ----------
thomas      2008-10-09 1000     2008-10-09
NULL        NULL       NULL     2008-10-10
NULL        NULL       NULL     2008-10-11
NULL        NULL       NULL     2008-10-12
NULL        NULL       NULL     2008-10-13
NULL        NULL       NULL     2008-10-14
NULL        NULL       NULL     2008-10-15
NULL        NULL       NULL     2008-10-16
NULL        NULL       NULL     2008-10-17
NULL        NULL       NULL     2008-10-18
NULL        NULL       NULL     2008-10-19
thomas      2008-10-20 5000     2008-10-20

有什么主意吗?

更新: 我最终使用光标。此版本可以完美运行,包括帐户没有条目的情况。

 DECLARE @Date datetime 
    declare @result table (accountname nvarchar(50),  balance int, date datetime)
    DECLARE @StartDate datetime = '2008/10/1';
    DECLARE @EndDate   datetime = '2008/10/29';


    declare cur cursor for
    WITH theDates AS
         (
            SELECT @StartDate as theDate
                UNION ALL
            SELECT DATEADD(day, 1, theDate)
                FROM theDates
            WHERE DATEADD(day, 1, theDate) <= @EndDate
         )
         select * from theDates

        open cur
        fetch next from cur into @date

        while @@FETCH_STATUS=0
        begin       


            insert into @result 

            select b.accountName, isnull(balance,
            (select isnull((select top 1 balance from accounts where date<@date and accountName=b.accountName order by date desc),0))       
            ), @date from 
                (select * from accounts where date = @date) a 
                right outer join (select distinct(accountname) from accounts ) b on a.accountname = b.accountname



            fetch next from cur into @date      
        end

        close cur
        deallocate cur

        select * from @result

2 个答案:

答案 0 :(得分:2)

尝试一下:

DECLARE @StartDate datetime = '2008/10/9';
DECLARE @EndDate   datetime = '2008/10/20';
WITH theDates AS
     (
        SELECT @StartDate as theDate
            UNION ALL
        SELECT DATEADD(day, 1, theDate)
            FROM theDates
        WHERE DATEADD(day, 1, theDate) <= @EndDate
     ),
acc AS(

    SELECT a.AccountName,
           a.Balance,
           a.Date,
           isnull(c.CloseDate, cast(GETDATE()as date)) as CloseDate
    FROM accounts a
    CROSS APPLY(SELECT MIN(b.Date) as CloseDate
                FROM accounts b
                WHERE b.Date > a.Date) c
                )

SELECT a.AccountName, a.Balance, a.Date, d.theDate
FROM acc a, theDates d
WHERE a.Date <= d.theDate
AND a.CloseDate > d.theDate
option (maxrecursion 0)

结果:

AccountName Balance     Date                theDate
----------- ----------- ------------------- -----------------------
thomas      1000        2008-10-09 00:00:00 2008-10-09 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-10 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-11 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-12 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-13 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-14 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-15 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-16 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-17 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-18 00:00:00.000
thomas      1000        2008-10-09 00:00:00 2008-10-19 00:00:00.000
thomas      5000        2008-10-20 00:00:00 2008-10-20 00:00:00.000

答案 1 :(得分:1)

您可以尝试使用聚合函数MINMAX创建日历表,然后使用OUTER JOIN

WITH theDates AS
(
        SELECT AccountName, MIN(Date) as StartDt,MAX(Date) EndDt
        FROM accounts 
        GROUP BY AccountName             
        UNION ALL
        SELECT AccountName,DATEADD(day, 1, StartDt),EndDt
        FROM theDates
        WHERE DATEADD(day, 1, StartDt) <= EndDt
)
select d.AccountName,
       d.StartDt [date],
       ISNULL(a.Balance,0) Balance 
from accounts a
LEFT join thedates d on a.date=d.StartDt
order by StartDt