SQL Server: GROUP BY Aggregation semantics with the PIVOT operator - sql-server

I am on SQL Server 2008 and I have a table containing WA metrics of the following form :
CREATE TABLE #VistitorStat
(
datelow datetime,
datehigh datetime,
name varchar(255),
cnt int
)
Two days worth of data in the table looks like so:
2009-07-25 00:00:00.000 2009-07-26 00:00:00.000 New Visitor 221
2009-07-25 00:00:00.000 2009-07-26 00:00:00.000 Unique Visitors 225
2009-07-25 00:00:00.000 2009-07-26 00:00:00.000 Return Visitors 0
2009-07-25 00:00:00.000 2009-07-26 00:00:00.000 Repeat Visitors 22
2009-07-26 00:00:00.000 2009-07-27 00:00:00.000 New Visitor 263
2009-07-26 00:00:00.000 2009-07-27 00:00:00.000 Unique Visitors 269
2009-07-26 00:00:00.000 2009-07-27 00:00:00.000 Return Visitors 4
2009-07-26 00:00:00.000 2009-07-27 00:00:00.000 Repeat Visitors 38
I want to group by the days and pivot the metrics into row form. The examples for using the PIVOT operator that I can find only show aggregation based on the SUM and MAX aggregate function. Presumably I need to convey GROUP BY semantics to the PIVOT operator -- note: I can't find any clear examples/ documentation on how to achieve this. Could someone please post the correct syntax of this -- with the use of the PIVOT operator -- of this query.
If this is not possible with pivot -- can you come up with an elegant way of writing the query ? If not I'll just have to generate the data in transposed form.
Post answer edit:
I have come to the conclusion that the pivot operator is unelegant (so far so that I consider it a syntax hack) -- I have solved the problem by generating the data in a transposed fashion. I welcome comments.

I m not sure of the result you want but this gives a line per day:
CREATE TABLE #VistitorStat
(
datelow datetime,
datehigh datetime,
name varchar(255),
cnt int
)
insert into #VistitorStat
select '2009-07-25 00:00:00.000','2009-07-26 00:00:00.000', 'New Visitor', 221
union select '2009-07-25 00:00:00.000',' 2009-07-26 00:00:00.000', 'Unique Visitors', 225
union select '2009-07-25 00:00:00.000',' 2009-07-26 00:00:00.000', 'Return Visitors', 0
union select '2009-07-25 00:00:00.000',' 2009-07-26 00:00:00.000', 'Repeat Visitors', 22
union select '2009-07-26 00:00:00.000',' 2009-07-27 00:00:00.000', 'New Visitor' , 263
union select '2009-07-26 00:00:00.000',' 2009-07-27 00:00:00.000', 'Unique Visitors', 269
union select '2009-07-26 00:00:00.000',' 2009-07-27 00:00:00.000', 'Return Visitors', 4
union select '2009-07-26 00:00:00.000',' 2009-07-27 00:00:00.000', 'Repeat Visitors', 38
select * from #VistitorStat
pivot (
sum(cnt)
for name in ([New Visitor],[Unique Visitors],[Return Visitors], [Repeat Visitors])
) p

Related

13 Period Calendar 4-4-5 Calendar T-SQL MSSQL

I am trying to create a 13 period calendar in mssql but I am a bit stuck. I am not sure if my approach is the best way to achieve this. I have my base script which can be seen below:
Set DateFirst 1
Declare #Date1 date = '20180101' --startdate should always be start of
financial year
Declare #Date2 date = '20181231' --enddate should always be start of
financial year
SELECT * INTO #CalendarTable
FROM dbo.CalendarTable(#Date1,#Date2,0,0,0)c
DECLARE #StartDate datetime,#EndDate datetime
SELECT #StartDate=MIN(CASE WHEN [Day]='Monday' THEN [Date] ELSE NULL END),
#EndDate=MAX([Date])
FROM #CalendarTable
;With Period_CTE(PeriodNo,Start,[End])
AS
(SELECT 1,#StartDate,DATEADD(wk,4,#StartDate) -1
UNION ALL
SELECT PeriodNo+1,DATEADD(wk,4,Start),DATEADD(wk,4,[End])
FROM Period_CTE
WHERE DATEADD(wk,4,[End])< =#EndDate
OR PeriodNo+1 <=13
)
select * from Period_CTE
Which gives me this:
PeriodNo Start End
1 2018-01-01 00:00:00.000 2018-01-28 00:00:00.000
2 2018-01-29 00:00:00.000 2018-02-25 00:00:00.000
3 2018-02-26 00:00:00.000 2018-03-25 00:00:00.000
4 2018-03-26 00:00:00.000 2018-04-22 00:00:00.000
5 2018-04-23 00:00:00.000 2018-05-20 00:00:00.000
6 2018-05-21 00:00:00.000 2018-06-17 00:00:00.000
7 2018-06-18 00:00:00.000 2018-07-15 00:00:00.000
8 2018-07-16 00:00:00.000 2018-08-12 00:00:00.000
9 2018-08-13 00:00:00.000 2018-09-09 00:00:00.000
10 2018-09-10 00:00:00.000 2018-10-07 00:00:00.000
11 2018-10-08 00:00:00.000 2018-11-04 00:00:00.000
12 2018-11-05 00:00:00.000 2018-12-02 00:00:00.000
13 2018-12-03 00:00:00.000 2018-12-30 00:00:00.000
The result i am trying to get is
Even if I have to take a different approach I would not mind, as long as the result is the same as the above.
dbo.CalendarTable() is a function that returns the following results. I can share the code if desired.
I'd create a general number's table like suggested here and add a column Periode13.
The trick to get the tiling is the integer division:
DECLARE #PeriodeSize INT=28; --13 "moon-months" a 28 days
SELECT TOP 100 (ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1)/#PeriodeSize
FROM master..spt_values --just a table with many rows to show the principles
You can add this to an existing numbers table with a simple update statement.
UPDATE A fully working example (using the logic linked above)
DECLARE #RunningNumbers TABLE (Number INT NOT NULL
,CalendarDate DATE NOT NULL
,CalendarYear INT NOT NULL
,CalendarMonth INT NOT NULL
,CalendarDay INT NOT NULL
,CalendarWeek INT NOT NULL
,CalendarYearDay INT NOT NULL
,CalendarWeekDay INT NOT NULL);
DECLARE #CountEntries INT = 100000;
DECLARE #StartNumber INT = 0;
WITH E1(N) AS(SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)), --10 ^ 1
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), -- 10 ^ 8 = 10,000,000 rows
CteTally AS
(
SELECT TOP(ISNULL(#CountEntries,1000000)) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) -1 + ISNULL(#StartNumber,0) As Nmbr
FROM E8
)
INSERT INTO #RunningNumbers
SELECT CteTally.Nmbr,CalendarDate.d,CalendarExt.*
FROM CteTally
CROSS APPLY
(
SELECT DATEADD(DAY,CteTally.Nmbr,{ts'2018-01-01 00:00:00'})
) AS CalendarDate(d)
CROSS APPLY
(
SELECT YEAR(CalendarDate.d) AS CalendarYear
,MONTH(CalendarDate.d) AS CalendarMonth
,DAY(CalendarDate.d) AS CalendarDay
,DATEPART(WEEK,CalendarDate.d) AS CalendarWeek
,DATEPART(DAYOFYEAR,CalendarDate.d) AS CalendarYearDay
,DATEPART(WEEKDAY,CalendarDate.d) AS CalendarWeekDay
) AS CalendarExt;
--The mockup table from above is now filled and can be queried
WITH AddPeriode AS
(
SELECT Number/28 +1 AS PeriodNumber
,CalendarDate
,CalendarWeek
,r.CalendarDay
,r.CalendarMonth
,r.CalendarWeekDay
,r.CalendarYear
,r.CalendarYearDay
FROM #RunningNumbers AS r
)
SELECT TOP 100 p.*
,(SELECT MIN(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber) AS [Start]
,(SELECT MAX(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber) AS [End]
,(SELECT MIN(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber AND x.CalendarWeek=p.CalendarWeek) AS [wkStart]
,(SELECT MAX(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber AND x.CalendarWeek=p.CalendarWeek) AS [wkEnd]
,(ROW_NUMBER() OVER(PARTITION BY PeriodNumber ORDER BY CalendarDate)-1)/7+1 AS WeekOfPeriode
FROM AddPeriode AS p
ORDER BY CalendarDate
Try it out...
Hint: Do not use a VIEW or iTVF for this.
This is non-changing data and much better placed in a physically stored table with appropriate indexes.
Not abundantly sure external links are accepted here, but I wrote an article that pulls of a 5-4-4 'Crop Year' fiscal year with all the code. Feel free to use all the code in these articles.
SQL Server Calendar Table
SQL Server Calendar Table: Fiscal Years

Longest gap between test matches in Sachin's career

I am new to SQL server and was practising using Sachin's batting stats (Cricket) I found here. (Sachin Batting Statistics). I wanted to find the longest gap between two test matches in Sachin's career. So basically have to filter it based on Test matches and find the max difference in the Start_DateAscending column? Hope that made some sense. Sample table added if link doesn't make sense
EDIT: I created a sample table with different dates. the column is named DateValues. Now, I want to find the code for maximum difference between any two successive rows in the DateValue column. For example, in this case the answer is 2 years and 17 days between December 09, 1989 and December 26, 1991
IF OBJECT_ID('TempDB..#mytable','U') IS NOT NULL
DROP TABLE #mytable
CREATE TABLE #mytable
(
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
DateValue DATETIME
)
SET DATEFORMAT DMY
SET IDENTITY_INSERT #mytable ON
INSERT INTO #mytable
(ID, DateValue)
SELECT '11', 'Nov 15 1989 12:00AM' UNION ALL
SELECT '59', 'Nov 23 1989 12:00AM' UNION ALL
SELECT '37', 'Dec 09 1989 12:00AM' UNION ALL
SELECT '44', 'Dec 26 1991 12:00AM' UNION ALL
SELECT '55', 'May 31 1993 12:00AM' UNION ALL
SELECT '60', 'May 15 1995 12:00AM' UNION ALL
SELECT '57', 'Jan 12 1996 12:00AM' UNION ALL
SELECT '43', 'Jan 19 1996 12:00AM' UNION ALL
SELECT '49', 'Jan 31 1996 12:00AM' UNION ALL
SELECT '18', 'Oct 17 1997 12:00AM'
Here's a solution I found on this website, the answer I obtained was 1900-01-01!
SELECT MAX(#mytable.DateValue-h.DateValue) as maxDiff
FROM #mytable
LEFT JOIN #mytable h
ON h.ID=[dbo].#mytable.ID AND #mytable.DateValue>=h.DateValue
WHERE h.DateValue IS NOT NULL
If you're using SQL Server 2012 or above, this SQL will return the biggest gap in days between two tests:
select max(datediff(day, a.TestDate, a.NextTest)) as BiggestGap
from (
select DateValue as TestDate, lead(DateValue) over (order by DateValue) as NextTest
from #mytable m
) a
The first thing this query does (inside the parenthesis) is gets a table that lists all test matches and the date of the next test match. That's what the innermost query provides: It selects all test dates and, using the lead function, the date of the match straight after that test.
The data from that parenthesised select (including ID) looks like this:
ID TestDate NextTest
----------- ----------------------- -----------------------
11 1989-11-15 00:00:00.000 1989-11-23 00:00:00.000
59 1989-11-23 00:00:00.000 1989-12-09 00:00:00.000
37 1989-12-09 00:00:00.000 1991-12-26 00:00:00.000
44 1991-12-26 00:00:00.000 1993-05-31 00:00:00.000
55 1993-05-31 00:00:00.000 1995-05-15 00:00:00.000
60 1995-05-15 00:00:00.000 1996-01-12 00:00:00.000
57 1996-01-12 00:00:00.000 1996-01-19 00:00:00.000
43 1996-01-19 00:00:00.000 1996-01-31 00:00:00.000
49 1996-01-31 00:00:00.000 1997-10-17 00:00:00.000
18 1997-10-17 00:00:00.000 NULL
After that (outside the parenthesis), it's simply a case of finding the row with the biggest difference between dates. In SQL Server, it's best to use the datediff function to get the difference between two dates instead of using mathematical operators such as - in the example you saw, so we use that to get the difference in days between each row. max is used to get the largest of those, thus returning the biggest gap between two matches.
Using the example SQL data provided, the biggest gap is 747 days (approximately 2 years 17 days).

SQL Server time sheet calculation

I have a time punch program the outputs the data set below. RECTYP_43 are the (1) in and (2) out punches. I need a query to look at the look at the LOGINDATE_43 and LOGINTIME_43 and the RECTYPE_43 and get the difference between 1 and 2.
I thought this would be easier than it has proven to be.
empid_43 RECTYPE_43 LOGINDATE_43 LOGINTIME_43
------------------------------------------------------------
127 1 2016-10-21 00:00:00.000 0558
127 2 2016-10-21 00:00:00.000 1430
127 2 2016-10-21 00:00:00.000 1201
127 1 2016-10-21 00:00:00.000 1228
127 1 2016-10-24 00:00:00.000 0557
127 2 2016-10-24 00:00:00.000 1200
127 1 2016-10-24 00:00:00.000 1228
127 2 2016-10-24 00:00:00.000 1430
2589 2 2016-10-21 00:00:00.000 1431
2589 1 2016-10-21 00:00:00.000 0556
2589 1 2016-10-24 00:00:00.000 0550
2589 2 2016-10-24 00:00:00.000 1431
2589 2 2016-10-24 00:00:00.000 1201
2589 1 2016-10-24 00:00:00.000 1226
69 1 2016-10-24 00:00:00.000 1229
69 2 2016-10-24 00:00:00.000 1430
69 1 2016-10-24 00:00:00.000 0555
69 2 2016-10-24 00:00:00.000 1200
You can use a CTE to get all the punch-ins and then a subquery to find the first punch out that comes after that time...
;WITH ctePunchIn AS (
SELECT empid_43, LOGINDATE_43 AS Date_In, LOGINTIME_43 AS Time_In
FROM #Table1
WHERE [RECTYPE_43] = 1
)
SELECT
empid_43, Date_In, Time_In
,(SELECT TOP 1 LOGINTIME_43 FROM #Table1 WHERE
(empid_43 = ctePunchIn.empid_43)
AND
(LOGINDATE_43 = ctePunchIn.Date_In)
AND
(LOGINTIME_43 > ctePunchIn.Time_In)
AND
(RECTYPE_43 = 2)
ORDER BY empid_43, Date_In, LOGINTIME_43) AS Time_Out
FROM
ctePunchIn
Dazedandconfused's answer works if the logout Time is the same date as the login time, but if the user logs out on a different day to logging in, it will not work.
e.g.
INSERT into Punch (empId_43, RecType_43, LoginDate_43, LoginTime_43)
VALUES (15, 1, '2016-01-01', '2305'),
(15, 2, '2016-01-02', '0005');
In order to accomodate for this, you need to know what the next item in the table is for that employee. And with that, you can ensure that the next item is also a logout event. This will help capture situations where someone has forgotten to punch out.
Extending the CTE can provide a more complete solution:
WITH Data AS
(
SELECT empId_43,
RecType_43,
LoginDate_43,
LoginTime_43,
RowNum = ROW_NUMBER() OVER (PARTITION BY empId_43
ORDER BY LoginDate_43, LoginTime_43)
FROM Punch
)
SELECT PIn.empId_43 [Employee],
PIn.LoginDate_43 [LoginDate],
PIn.LoginTime_43 [LoginTime],
POut.LoginDate_43 [LogoutDate],
POut.LoginTime_43 [LogoutTime]
FROM Data PIn
LEFT JOIN Data POut ON PIn.empId_43 = POut.empId_43
AND POut.RecType_43 = 2
AND POut.RowNum = PIn.RowNum + 1
WHERE PIn.RecType_43 = 1
ORDER BY PIn.empId_43, PIn.LoginDate_43, PIn.LoginTime_43;
However, Row_Number can be inefficient. Doing this is best when looking at a small subset (e.g. a particular date range, etc).
slightly different way of doing it:
select
punchIn.empid_43,
punchIn.login as dateTime_in,
punchout.login as dateTime_out
from
(
SELECT empId_43,
RecType_43,
LoginDate_43,
LoginTime_43,
dateadd('n',right(logintime_43,2),
dateadd('hh',left(LoginTime_43,2),
LoginDate_43)) as login,
RowNum = ROW_NUMBER() OVER (PARTITION BY empId_43
ORDER BY LoginDate_43, LoginTime_43)
FROM Punch
where rectype_43 = 1
) punchIn left outer join
(
SELECT empId_43,
RecType_43,
LoginDate_43,
LoginTime_43,
dateadd('n',right(logintime_43,2),
dateadd('hh',left(LoginTime_43,2),
LoginDate_43)) as login,
RowNum = ROW_NUMBER() OVER (PARTITION BY empId_43
ORDER BY LoginDate_43, LoginTime_43)
FROM Punch
where rectype_43 = 2
) punchOut on
punchin.empID = punchout.empID and
punchin.rownum = punchout.rownum
assuming all punchin rows have a corresponding punchout row

sum 1 column and pick the date on another column

I have a table with 2 columns:
date | points
Data:
2015-01-30 00:00:00.000 | 1.2
2015-01-29 00:00:00.000 | 2
2015-01-30 00:00:00.000 | 5
2015-01-27 00:00:00.000 | 7
I want to sum point column based on date. So if I filter date with 2015-01-30 00:00:00.000 then the result would be like the one below:
2015-01-30 00:00:00.000 | 7.5
The record above is what it should look like.
I have a query but it returns
Error converting data type varchar to float.
My SQL code.
SELECT gpsdate, totkm
FROM (
SELECT gpsdate,
cast(cast(cast((SUM(KMRUN)) as float) as int) as nvarchar(50)) as totkm
,
RANK() OVER(PARTITION BY gpsdate
ORDER BY SUM(KMRUN) DESC) as R
FROM view_tracklist_report
GROUP BY gpsdate) as InnerQuery
WHERE InnerQuery.R = 1
Test Data
CREATE TABLE #Test ([date] DATETIME, points FLOAT);
INSERT INTO #Test
([date], points)
VALUES
('2015-01-30 00:00:00.000', 1.2),
('2015-01-29 00:00:00.000', 2),
('2015-01-30 00:00:00.000', 5),
('2015-01-27 00:00:00.000', 7)
Actual Code: Not sure why it should sum to 7.5 tho? 5+1.2=6.2
SELECT DISTINCT [date], SUM(points) OVER(PARTITION BY [date]) AS TotPoints
FROM #Test
Just group by:
Select gpsdate, Sum(CAST(KMRUN AS float)) as KMRUN
From view_tracklist_report
group BY gpsdate
This is not a good choice to store numerical values as varchars. If you do so you will have to convert them to numbers in every query. And this is not optimal.
So you have to convert your column tu FLOAT. Then you can simply call
SUM(KMRUN)
without any casting.
Now your SUM(KMRUN) is concatenating strings and giving result like
1.2257

Fetching dates monthly from the table

Can you help out with a problem
I have table price table which has daily prices starting 31st Dec 2010 till todays date.The table contains daily prices
2009-12-31 00:00:00.000 1.0020945351
2010-01-01 00:00:00.000 1.0021009300
2010-01-04 00:00:00.000 1.0021910181
2010-01-05 00:00:00.000 1.0022005986
2010-01-06 00:00:00.000 1.0022428696
2010-01-07 00:00:00.000 1.0022647147
2010-01-08 00:00:00.000 1.0022842726
2010-01-11 00:00:00.000 1.0023374302
2010-01-12 00:00:00.000 1.0023465374
2010-01-13 00:00:00.000 1.0023638081
2010-01-14 00:00:00.000 1.0023856533
2010-01-00 00:00:00.000 1.0024083955
2010-01-18 00:00:00.000 1.0024779677
2010-01-19 00:00:00.000 1.0025020553
2010-01-20 00:00:00.000 1.002521135
2010-01-21 00:00:00.000 1.0025420688
2010-01-22 00:00:00.000 1.0025593397
2010-01-25 00:00:00.000 1.0026180146
2010-01-26 00:00:00.000 1.002637573
2010-01-27 00:00:00.000 1.0026648447
2010-01-28 00:00:00.000 1.0026957934
2010-01-29 00:00:00.000 1.0027267421
2010-02-01 00:00:00.000 1.0028195885
2010-02-02 00:00:00.000 1.0028573523
2010-02-03 00:00:00.000 1.0028964611
2010-02-04 00:00:00.000 1.00293557
2010-02-05 00:00:00.000 1.002973334
2010-02-08 00:00:00.000 1.0030879717
2010-02-09 00:00:00.000 1.0031279777
2010-02-10 00:00:00.000 1.003171166
2010-02-11 00:00:00.000 1.0032007452
2010-02-12 00:00:00.000 1.0032575895
2010-02-00 00:00:00.000 1.0033749191
2010-02-1 00:00:00.000 1.0034140292
2010-02-17 00:00:00.000 1.003452691
2010-02-18 00:00:00.000 1.0034918013
2010-02-19 00:00:00.000 1.0035395633
2010-02-22 00:00:00.000 1.0036664439
2010-02-23 00:00:00.000 1.0037042097
2010-02-24 00:00:00.000 1.0037510759
2010-02-25 00:00:00.000 1.0038001834
2010-02-26 00:00:00.000 1.003850077
I need to write a query to get index based on
(Last day of current month/Previous month last day) - 1 * 100.So that output comes something like this
31-Jan-10 0.01%
28-Feb-10 0.02%
31-Mar-10 0.00%
Following is one of the solution I thought about however please share best ideas to implement this problem
Extract last day of all the months with values into a temp table and then order by dates so that they subtract and put the values into another temp table
Looking forward to your help.
Try this....
DECLARE #StartDate DATETIME = '2010-01-01',
#EndDate DATETIME = GETDATE();
WITH data AS (
SELECT 1 AS i, CONVERT(DATETIME, NULL) AS StartDate, DATEADD(MONTH, 0, #StartDate) - 1 AS EndDate
UNION ALL
SELECT i + 1, data.EndDate, DATEADD(MONTH, i, #StartDate) - 1 AS EndDate
FROM data
WHERE DATEADD(MONTH, i, #StartDate) - 1 < #EndDate
)
SELECT (
((SELECT TOP 1 Rate FROM RateTable WHERE Date <= data.EndDate ORDER BY Date DESC) /
(SELECT TOP 1 Rate FROM RateTable WHERE Date <= data.StartDate ORDER BY Date DESC)- 1) * 100)
FROM DATA -- parenthesis were causing issues
WHERE data.StartDate IS NOT NULL
OPTION (MAXRECURSION 10000);
You'll need to replace the
(SELECT Rate FROM RateTable WHERE Date = data.StartDate)
and
(SELECT Rate FROM RateTable WHERE Date = data.EndDate)
With the values for your rate table. as you didn't mention column and table names in your question.
rwking indicated that there might be gaps in the rates table that would cause issues.
I've modified the subquery to bring back the first rate on or nearest the start and end dates.
Hope that helps
You can use the LAG function introduced in SQL2012 to make it a bit easier:
WITH DataWithOrder AS
(
SELECT DateField, PriceField,
ROW_NUMBER() OVER(PARTITION BY YEAR(DateField), Month(DateField) ORDER BY DateField DESC) AS Pos
FROM PriceTable
)
SELECT
DateField,
PriceField,
LAG(PriceField) OVER(ORDER BY DateField) AS PriceLastMonth,
((PriceField / LAG(PriceField) OVER(ORDER BY DateField)) - 1) * 100 AS PCIncrease
FROM DataWithOrder
WHERE Pos = 1
ORDER BY DateField
I took a very different approach than the other guy. His is more elegant and would work better if the daily data does represent every single day of every month. If there are gaps in days, however, as your sample data represents, you can try the following code.
with cte as (select mydate
, price
, ROW_NUMBER() over(partition by YEAR(mydate), MONTH(mydate)
order by day(mydate) desc) row_n
from #temp)
select mydate, price, ROW_NUMBER() over(order by mydate desc) row_num
into #temp2
from cte
where row_n = 1
alter table #temp2
add idx float
declare #counter int = 1
while #counter < (select MAX(row_num)+1 from #temp2)
begin
update t2
set t2.idx = ((t2.price/t3.price)-1)*100
from #temp2 t2 left join
#temp2 t3 on 1 = 1
where t2.row_num = #counter and t3.row_num = #counter + 1
set #counter = #counter + 1
end
select mydate, idx
from #temp2
As the other poster mentioned, you didn't provide column or table names. My process was to insert your data into a table called [#temp] with column names [mydate] and [price].
Also, the data sample you provided contains two invalid dates that I changed to arbitrary dates just for the purposes of getting code to run. (2010-01-00 and 2010-02-00)

Resources