Given that you make reference to the row_number window function in your question, I am going to assume that you are on at least SQL Server 2012.
Sample Data:
create table #myTable
(
MyDate datetime
, SalesTotal decimal(10,2)
)
insert into #myTable
values ('2017-12-14', 90.00)
, ('2017-12-15', 92.00)
, ('2017-12-18', 96.00)
, ('2017-12-19', 97.00)
, ('2017-12-20', 94.00)
, ('2017-12-21', 99.00)
, ('2017-12-22', 100.00)
Answer:
You can take advantage of the lag/lead window functions to compare values between rows. Note that the sub-query has the MyDate value of 2017-12-14 in the record set because it needs to be present to get the SalesTotal value for comparison, then the top level query filters that record out.
declare @bgn_dt date = '2017-12-15' --set by OP
, @end_dt date = '2017-12-22' --set by OP
, @lag_dt date;
set @lag_dt = (select max(MyDate) from #myTable where MyDate < @bgn_dt) --get the "yesterday" that the @bgn_dt will need
select a.MyDate
, a.SalesTotal
, format(((1.0 * a.SalesTotal) / a.SalesTotalPrevDay) - 1, '0%') as SalesTotalChange
from (
select t.MyDate
, t.SalesTotal
, lag(t.SalesTotal, 1, NULL) over (/*partition by (if needed)*/ order by t.MyDate asc) as SalesTotalPrevDay
from #myTable as t
where 1=1
and t.MyDate between @lag_dt and @end_dt
) as a
where 1=1
and a.MyDate >= @bgn_dt
Output:
+-------------------------+------------+------------------+
| MyDate | SalesTotal | SalesTotalChange |
+-------------------------+------------+------------------+
| 2017-12-15 00:00:00.000 | 92.00 | 2% |
| 2017-12-18 00:00:00.000 | 96.00 | 4% |
| 2017-12-19 00:00:00.000 | 97.00 | 1% |
| 2017-12-20 00:00:00.000 | 94.00 | -3% |
| 2017-12-21 00:00:00.000 | 99.00 | 5% |
| 2017-12-22 00:00:00.000 | 100.00 | 1% |
+-------------------------+------------+------------------+
Update:
In response to Pரதீப்'s comment, I thought I'd explain why someone might use where 1=1 in their query even though it seems unnecessary. Most of the time it is used to initialize the where clause in SQL statement built at run time (Dynamic SQL). Another use for it is in development/debugging efforts where you may be commenting in/out various constraints including the first listed in the where clause. In the end, it has no impact on the performance of the query, but may make your life easier.
Update 2:
To explain further as to why, per stackonfire's description, the first record is always null on the inner query. All window functions are only concerned with records that are in the current query.
For example, if you look at the query below, you would want row_number to return 1, 2, 3 (as opposed to 1, 2, 4). The same is true of a lag/lead function, that some record has to be the first/last therefore there is no previous/next record to retrieve a value from.
I have updated my initial answer to add the dates necessary to the where clause.
create table #letters
(
letter char(1)
)
insert into #letters
values ('a'), ('b'), ('c'), ('d')
select *
, row_number() over (order by l.letter asc) as row_nbr
from #letters l
where l.letter <> 'c'