Как получить first_value из предыдущего раздела окна - PullRequest
0 голосов
/ 01 мая 2020

Я хочу отобразить значение 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

Ответы [ 3 ]

2 голосов
/ 01 мая 2020

Вы можете использовать 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);
1 голос
/ 01 мая 2020

Мы могли бы использовать 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;

screen capture of demo below

Демо

0 голосов
/ 01 мая 2020

Если вы хотите сделать это, используя только оконные функции, вы можете использовать:

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 <> date . . . ).

Здесь - это db <> скрипка.

Примечание что в базах данных, которые полностью поддерживают спецификацию окна range, это можно сделать напрямую с помощью logi c следующим образом:

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

Увы, SQL Сервер не поддерживает эту (стандартную) функциональность.

...