【问题标题】:How to get first_value from previous window partition如何从前一个窗口分区中获取 first_value
【发布时间】:2020-08-15 19:35:06
【问题描述】:

我想在查询中显示前一天的 BalanceEndOfYesterday 值,如下所示。

| Date       | Amout | BalanceEndOfDay | BalanceEndOfYesterday |
|------------|-------|-----------------|-----------------------|
| 2020-04-30 | 10    | 130             | 80                    |
| 2020-04-30 | 20    | 130             | 80                    |
| 2020-04-30 | 30    | 130             | 80                    |
| 2020-04-30 | -10   | 130             | 80                    |
| 2020-04-29 | 50    | 80              | 0                     |
| 2020-04-29 | -10   | 80              | 0                     |
| 2020-04-29 | 40    | 80              | 0                     |

我的查询是

SELECT 
    BalanceEndOfDay ,
    first_value(BalanceEndOfDay) OVER (ORDER BY Date DESC) -- here is some sort of window needed
FROM AccountTransactions

【问题讨论】:

    标签: sql tsql sql-server-2012 window-functions


    【解决方案1】:

    您可以使用apply

    SELECT at.*, COALESCE(at1.BalanceEndOfDay, 0) AS BalanceEndOfYesterday
    FROM AccountTransactions at OUTER APPLY
         ( SELECT TOP (1) at1.BalanceEndOfDay
           FROM AccountTransactions at1
           WHERE at1.Date < at.Date
           ORDER BY at1.Date DESC
         ) at1;
    

    编辑:如果您只想要昨天的余额,那么您可以使用dateadd()

    SELECT DISTINCT at.*, COALESCE(at1.balanceendofday, 0) AS BalanceEndOfYesterday
    FROM AccountTransactions at LEFT JOIN
         AccountTransactions at1
         ON at1.date = dateadd(day, -1, at.date);
    

    【讨论】:

    • 根据我对问题的解释,我很想使用at1.date = dateadd(day, -1, at.date)
    【解决方案2】:

    我们可以在这里使用LAG,在首先按日期聚合以获得每个日期的单一日终余额之后。然后,我们可以将您的表格加入到此结果中,以提取昨天的日终余额。

    WITH cte AS (
        SELECT Date, MAX(BalanceEndOfDay) AS BalanceEndOfDay,
            LAG(MAX(BalanceEndOfDay), 1, 0) OVER (ORDER BY Date) As BalanceEndOfYesterday
        FROM AccountTransactions
        GROUP BY Date
    )
    
    SELECT
        a1.Date,
        a1.Amount,
        a1.BalanceEndOfDay,
        a2.BalanceEndOfYesterday
    FROM AccountTransactions a1
    INNER JOIN cte a2
        ON a1.Date = a2.Date
    ORDER BY
        a1.Date DESC;
    

    Demo

    【讨论】:

      【解决方案3】:

      如果您只想使用窗口函数来执行此操作,您可以使用:

      select at.*,
             max(case when prev_date = dateadd(day, -1, date) then prev_BalanceEndOfDay end) over (partition by date) as prev_BalanceEndOfDay
      from (select at.*,
                   lag(BalanceEndOfDay) over (order by date) as prev_BalanceEndOfDay,
                   lag(date) over (order by date) as prev_date
            from accounttransactions at
           ) at;
      

      注意:这将“前一天”解释为正好是前一天。意思是“数据中的前一天”,那么第一个比较应该是max(case when prev_date &lt;&gt; date . . . )

      Here 是一个 dbfiddle。

      请注意,在完全支持range 窗口规范的数据库中,这可以直接使用如下逻辑来完成:

      max(BalanceEndOfDay) over (order by datediff(day, '2000-01-01', date)
                                 range between 1 preceding and 1 preceding
                                )
      

      唉,SQL Server 不支持这个(标准)功能。

      【讨论】:

        猜你喜欢
        • 2021-07-11
        • 2017-01-04
        • 2016-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-26
        相关资源
        最近更新 更多