Find Non Consecutive date in SQL Server - sql-server

I want to find the missing NON-consecutive dates between two consecutive date.
I am posting my SQL query and temp tables to find out the results.
But I am not getting the proper results
Here is my SQL Query
drop table #temp
create table #temp(an varchar(20),dt date)
insert into #temp
select '2133783715' , '2016-10-16' union all
select '5107537880' , '2016-10-15' union all
select '6619324250' , '2016-10-15' union all
select '7146586717' , '2016-10-15' union all
select '7472381321' , '2016-10-12' union all
select '7472381321' , '2016-10-13' union all
select '7472381321' , '2016-10-14' union all
select '7472381321' , '2016-10-24' union all
select '8186056340' , '2016-10-15' union all
select '9099457123' , '2016-10-12' union all
select '9099457123' , '2016-10-13' union all
select '9099457123' , '2016-10-14' union all
select '9099457123' , '2016-10-23' union all
select '9099457123' , '2016-11-01' union all
select '9099457123' , '2016-11-02' union all
select '9099457123' , '2016-11-03' union all
select '9165074784' , '2016-10-16'
drop table #final
SELECT an,MIN(dt) AS MinDate,MAX(dt) AS MaxDate, COUNT(*) AS ConsecutiveUsage
--DateDiff(Day,LAG(MAX(dt)) OVER (partition by an ORDER BY an),MAX(dt)) nonusageDate
into #final
FROM(
SELECT an,dt,
DATEDIFF(D, ROW_NUMBER() OVER(partition by an ORDER BY dt),dt) AS Diff
FROM #temp c
)P
GROUP BY an,diff
select * from #final order by 1
an MinDate MaxDate ConsecutiveUsage
2133783715 2016-10-16 2016-10-16 1
5107537880 2016-10-15 2016-10-15 1
6619324250 2016-10-15 2016-10-15 1
7146586717 2016-10-15 2016-10-15 1
7472381321 2016-10-12 2016-10-14 3
7472381321 2016-10-24 2016-10-24 1
7472381321 2016-10-27 2016-10-28 1
8186056340 2016-10-15 2016-10-15 1
9099457123 2016-10-12 2016-10-14 3
9099457123 2016-10-23 2016-10-23 1
9165074784 2016-10-16 2016-10-16 1
But I want results of non-usage date.
I want to get those AN which has not been used continuously since 10 days.
So here output should be like this:-
an minusagesdate maxusagedate ConsecutiveNotUseddays
7472381321 2016-10-15 2016-10-23 9
7472381321 2016-10-25 2016-10-26 2
9099457123 2016-10-15 2016-10-22 8
So I just want to find out only consecutive not used dates count and their min and max dates .

try this :
with ranked as (
select f1.*,
ROW_NUMBER() over(partition by an order by dt) rang
from #temp f1
where exists
(select * from #temp f2
where f1.an=f2.an and datediff( day, f2.dt, f1.dt) >1
)
)
select an, minusagesdate, maxusagesdate, ConsecutiveNotUseddays
from (
select f1.*,
DATEADD(DAY,1, (select f2.dt from ranked f2 where f1.an=f2.an and f2.rang+1=f1.rang)) minusagesdate ,
DATEADD(DAY,-1, f1.dt) maxusagesdate ,
datediff( day, (select f2.dt from ranked f2 where f1.an=f2.an and f2.rang+1=f1.rang), f1.dt) - 1 ConsecutiveNotUseddays
from ranked f1
) tmp
where tmp.ConsecutiveNotUseddays>0
or like this
with ranked as (
select f1.*,
ROW_NUMBER() over(partition by an order by dt) rang
from #temp f1
where exists
(select * from #temp f2
where f1.an=f2.an and datediff( day, f2.dt, f1.dt) >1
)
)
select f1.an,
DATEADD(DAY,1, f3.dtbefore) minusagesdate ,
DATEADD(DAY,-1, f1.dt) maxusagesdate ,
datediff( day, f3.dtbefore, f1.dt) - 1 ConsecutiveNotUseddays
from ranked f1
outer apply
(
select top 1 f2.dt as dtbefore from ranked f2
where f1.an=f2.an and f2.rang+1=f1.rang
) f3
where datediff( day, f3.dtbefore, f1.dt) - 1>0

It looks like you're trying to count the number of days not used between the mindate and the maxdate for each an. If that's the case, then this should do the trick:
select an, min(dt) as min_dt, max(dt) as max_dt
, count(distinct dt) as daysused --this counts each day used, but only once
, datediff(day,min(dt),max(dt)) as totaldays --this is the total number of days between min and max date
, datediff(day,min(dt),max(dt)) - count(distinct dt) as daysnotused
--This takes total days - used days to give non-used days
from #temp c
group by an
having datediff(day,min(dt),max(dt)) - count(distinct dt) >= 10

As I understood you need this:
;WITH cte AS (
SELECT an,
dt,
ROW_NUMBER() OVER (PARTITION BY an ORDER BY dt) as rn
FROM #temp
)
SELECT c1.an,
c1.dt MinDate,
c2.dt MaxDate,
DATEDIFF(day,c1.dt,c2.dt) as ConsecutiveNotUseddays
FROM cte c1
INNER JOIN cte c2
ON c1.an = c2.an AND c1.rn = c2.rn-1
WHERE DATEDIFF(day,c1.dt,c2.dt) >= 10
Output:
an MinDate MaxDate ConsecutiveNotUseddays
7472381321 2016-10-14 2016-10-24 10
For 9099457123 I got two rows with 9 in ConsecutiveNotUseddays. You can check results removing WHERE statement.

On any newer version of SQL Server this should be easy:
with x as (
select *, lag(dt) over(partition by an order by dt) dt_lag
from #temp
)
select *, datediff(day, dt_lag, dt)
from x
where datediff(day, dt_lag, dt) >= 10

Related

JOIN (VALUES (0),(1),(2),(3),...... ON Logic

SQL-SERVER 2017
SQL-FIDDLE
DB-CODE:
CREATE TABLE [TABLE_1] (
PLAN_NR decimal(28,6) NULL,
START_DATE datetime NULL);
INSERT INTO TABLE_1
(PLAN_NR,START_DATE)
VALUES
(1,'2020-05-01'),
(2,'2020-08-01');
My question is about the Syntax of the following Select:
WITH Dates AS(
SELECT T1.PLAN_NR,
V.I+1 AS PERIOD_NR,
DATEADD(DAY, 7*V.I, T1.START_DATE) AS START_DATE,
LEAD(DATEADD(DAY, 7*V.I, T1.START_DATE)) OVER (PARTITION BY PLAN_NR ORDER BY V.I) AS END_DATE
FROM dbo.TABLE_1 T1
------------------------------------------------
--> JOIN (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) V(I) ON 1000 >= V.I) <-- THIS LINE
------------------------------------------------
SELECT D.PLAN_NR,
D.PERIOD_NR,
V.START_DATE
FROM Dates D
CROSS APPLY (VALUES(START_DATE),(CASE WHEN MONTH(START_DATE) != MONTH(END_DATE) THEN
DATEADD(MONTH,DATEDIFF(MONTH,0,END_DATE),0) END)) V(START_DATE)
WHERE V.START_DATE IS NOT NULL
What is the logic to extend the values here to e.g. 1000?
Do I have to write out VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)......(1000)?
Edit:
I got the code mentioned here from Larnu answer to another question:
here.
I would create an extended tally:
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS
(SELECT 0 AS I
UNION ALL
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1,
N N2,
N N3),
Dates AS
(SELECT T1.PLAN_NR,
T.I + 1 AS PERIOD_NR,
DATEADD(DAY, 7 * T.I, T1.START_DATE) AS START_DATE,
LEAD(DATEADD(DAY, 7 * T.I, T1.START_DATE)) OVER (PARTITION BY PLAN_NR ORDER BY T.I) AS END_DATE
FROM dbo.TABLE_1 T1
CROSS JOIN Tally T)
SELECT D.PLAN_NR,
D.PERIOD_NR,
V.START_DATE
FROM Dates D
CROSS APPLY (VALUES (START_DATE),
(CASE
WHEN MONTH(START_DATE) != MONTH(END_DATE) THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, END_DATE), 0)
END)) V (START_DATE)
WHERE V.START_DATE IS NOT NULL;
You don't need, you can have a CTE to generate the number and join in like following.
WITH cteNum
AS (
SELECT 1 AS I
UNION ALL
SELECT I + 1
FROM cteNum
WHERE I + 1 <= 1000
)
Your final query will look like
with cteNum as
(
select 1 as I
union all
select I +1 from cteNum
where I + 1<=1000
), Dates AS(
SELECT T1.PLAN_NR,
V.I+1 AS PERIOD_NR,
DATEADD(DAY, 7*V.I, T1.START_DATE) AS START_DATE,
LEAD(DATEADD(DAY, 7*V.I, T1.START_DATE)) OVER (PARTITION BY PLAN_NR ORDER BY V.I) AS END_DATE
FROM dbo.TABLE_1 T1
JOIN cteNum V ON 1000 >= V.I)
SELECT D.PLAN_NR,
D.PERIOD_NR,
V.START_DATE
FROM Dates D
CROSS APPLY (VALUES(START_DATE),(CASE WHEN MONTH(START_DATE) != MONTH(END_DATE) THEN DATEADD(MONTH,DATEDIFF(MONTH,0,END_DATE),0) END)) V(START_DATE)
WHERE V.START_DATE IS NOT NULL
option (maxrecursion 0)
SQL-FIDDLE

TSQL - Groups and Islands dates

I need a help on writing an optimal query for the below problem. Have attached the query I have with me but it is highly utilizing resources.
Below is the code to achieve above said logic. Please suggest some optimal way to achieve the same
-- drop table #me
create table #ME (memid int , EffectiveDate datetime , termdate datetime)
Insert into #ME values ('123','3-Dec-16','10-Jan-17')
Insert into #ME values ('123','11-Jan-17','6-Feb-17')
Insert into #ME values ('123','7-Feb-17','5-Mar-17')
Insert into #ME values ('123','8-Mar-17','15-Apr-17')
Insert into #ME values ('123','16-Apr-17','24-May-17')
--drop table #dim
select * from #ME
declare #StartDate datetime , #CutoffDate datetime
select #StartDate= min(effectivedate),#CutoffDate = max(termdate) From #me where termdate<>'9999-12-31 00:00:00.000'
SELECT d
into #dim
FROM
(
SELECT d = DATEADD(DAY, rn - 1, #StartDate)
FROM
(
SELECT TOP (DATEDIFF(DAY, #StartDate, #CutoffDate))
rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
-- on my system this would support > 5 million days
ORDER BY s1.[object_id]
) AS x
) AS y;
--drop table #MemEligibilityDateSpread
select MemID, D As DateSpread Into #MemEligibilityDateSpread From #Dim dim JOIN #me ME on dim.d between ME.effectivedate and me.termdate
--drop table #DateClasified
WITH CTE AS
(
SELECT MEmID,
UniqueDate = DateSpread,
DateGroup = DATEADD(dd, - ROW_NUMBER() OVER (PARTITION BY Memid ORDER BY Memid,DateSpread), DateSpread)
FROM #MemEligibilityDateSpread
GROUP BY Memid,DateSpread
)
--===== Now, if we find the MIN and MAX date for each DateGroup, we'll have the
-- Start and End dates of each group of contiguous daes. While we're at it,
-- we can also figure out how many days are in each range of days.
SELECT Memid,
StartDate = MIN(UniqueDate),
EndDate = MAX(UniqueDate)
INTO #DateClasified
FROM cte
GROUP BY Memid,DateGroup
ORDER BY Memid,StartDate
select ME.MemID,ME.EffectiveDate,ME.TermDate,DC.StartDate,DC.EndDate from #DateClasified dc join #me ME ON Me.MemID = dc.MemID
and (ME.EffectiveDate BETWEEN DC.StartDate AND DC.EndDate
OR ME.TermDate BETWEEN DC.StartDate AND DC.EndDate)
In cte0 and cte1, we create an ad-hoc tally/calendar table. Once we have that, it is a small matter to calculate and group by Island.
Currently, the tally is has a max of 10,000 days (27 years), but you can easily expand the tally table by adding , cte0 N5
;with cte0(N) as (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N))
,cte1(R,D) as (Select Row_Number() over (Order By (Select Null))
,DateAdd(DD,-1+Row_Number() over (Order By (Select Null)),(Select MinDate=min(EffectiveDate) From #ME))
From cte0 N1, cte0 N2, cte0 N3, cte0 N4)
Select MemID
,EffectiveDate
,TermDate
,SinceFrom = Min(EffectiveDate) over (Partition By Island)
,Tildate = Max(TermDate) over (Partition By Island)
From (
Select *,Island = R - Row_Number() over (Partition By MemID Order by TermDate)
From #ME A
Join cte1 B on D Between EffectiveDate and TermDate
) A
Group By MemID,Island,EffectiveDate,TermDate
Order By 1,2
Returns
MemID EffectiveDate TermDate SinceFrom Tildate
123 2016-12-03 2017-01-10 2016-12-03 2017-03-05
123 2017-01-11 2017-02-06 2016-12-03 2017-03-05
123 2017-02-07 2017-03-05 2016-12-03 2017-03-05
123 2017-03-08 2017-04-15 2017-03-08 2017-05-24
123 2017-04-16 2017-05-24 2017-03-08 2017-05-24
Edit - Now if you want a compressed dataset
Select MemID
,EffectiveDate = Min(EffectiveDate)
,TermDate = Max(TermDate)
From (
Select *,Island = R - Row_Number() over (Partition By MemID Order by TermDate)
From #ME A
Join cte1 B on D Between EffectiveDate and TermDate
) A
Group By MemID,Island
Order By 1,2
Returns
MemID EffectiveDate TermDate
123 2016-12-03 2017-03-05
123 2017-03-08 2017-05-24

Return value from function in SQL Server

I want to get the last Saturday from today + 21 days.
In order to achieve this, I have written this script shown below. But the problem is that I can't get success to return the value from the result.
I want to create this function in SQL Server and will get this value in a stored procedure where I want.
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
DECLARE #NumOfDays INT
DECLARE #resultDate smalldatetime
SET #StartDate = GETDATE()
SET #EndDate = GETDATE()+21
SET #NumOfDays = DATEDIFF(DD,#StartDate , #EndDate) + 1 ;
WITH Tens AS
(
SELECT 1 N UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1
),
HUNDREDS AS
(
SELECT T1.N FROM TENS T1 CROSS JOIN TENS T2
),
THOUSANDS AS
(
SELECT T1.N FROM HUNDREDS T1 CROSS JOIN HUNDREDS T2
),
Numbers AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) RN FROM THOUSANDS
)
SELECT TOP 1
DATEADD(DD, (RN - 1), #StartDate) SaturdayDates
FROM
Numbers
WHERE
RN <= #NumOfDays
AND DATENAME (WEEKDAY, (DATEADD(DD, (RN - 1), #StartDate))) = 'Saturday'
ORDER BY
SaturdayDates DESC
Can you please guide me to achieve my goal? Thanks
Just rewrite it like this table-valued function:
CREATE FUNCTION dbo.Get_NextSaturdayDay()
RETURNS TABLE
AS
RETURN
(
-- Add the SELECT statement with parameter references here
WITH Tens AS
(
SELECT 1 N UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1
),
HUNDREDS AS
(
SELECT T1.N FROM TENS T1 CROSS JOIN TENS T2
),
THOUSANDS AS
(
SELECT T1.N FROM HUNDREDS T1 CROSS JOIN HUNDREDS T2
),
Numbers AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) RN FROM THOUSANDS
)
SELECT TOP 1 DATEADD( DD,(RN - 1) , GETDATE() ) as SaturdayDates
FROM
Numbers
WHERE
RN <= (DATEDIFF(DD,GETDATE() , DATEADD(day,21,GETDATE()) ) + 1) AND DATENAME ( WEEKDAY, (DATEADD( DD,(RN - 1) , GETDATE() )) ) = 'Saturday'
ORDER BY SaturdayDates DESC
)
GO
Than do:
SELECT *
FROM dbo.Get_NextSaturdayDay()
Output:
SaturdayDates
2016-10-15 11:02:33.570
If you need scalar-valued function:
CREATE FUNCTION dbo.Get_NextSaturdayDay ()
RETURNS datetime
AS
BEGIN
DECLARE #datetime datetime
;WITH Tens AS
(
SELECT 1 N UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 1
),
HUNDREDS AS
(
SELECT T1.N FROM TENS T1 CROSS JOIN TENS T2
),
THOUSANDS AS
(
SELECT T1.N FROM HUNDREDS T1 CROSS JOIN HUNDREDS T2
),
Numbers AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) RN FROM THOUSANDS
)
SELECT TOP 1 #datetime = DATEADD( DD,(RN - 1) , GETDATE() )
FROM
Numbers
WHERE
RN <= (DATEDIFF(DD,GETDATE() , DATEADD(day,21,GETDATE()) ) + 1) AND DATENAME ( WEEKDAY, (DATEADD( DD,(RN - 1) , GETDATE() )) ) = 'Saturday'
ORDER BY DATEADD( DD,(RN - 1) , GETDATE() ) DESC
-- Return the result of the function
RETURN #datetime
END
GO
Then run:
SELECT dbo.Get_NextSaturdayDay()
Output:
2016-10-15 11:02:33.570

how to fetch record monthly total in select query in sql server 2005

I am having following output of query
Query:
SELECT DATENAME(mm, date) [Month], sum(braekTime) [TotalBreakTime],
sum(DATEPART(hh,totalTime) * 60 + DATEPART(mi,totalTime) + DATEPART(ss,totalTime) * 0.017) [Minute],firstName
FROM employeeAttendance,employee
where FK_employeeId = employee.employeeId
GROUP BY DATENAME(mm, date),firstName
ORDER BY [Month]
but I want each n every month record with null/ 0 value
like June and July record is not available then it should display like following
Month TotalBreakTime Minute firstName
----- -------------- ------ ---------
January 0 0 NULL
February 0 0 NULL
March 0 0 NULL
April 0 0 NULL
May 50 1015.000 foramaa
June 0 0 NULL
July 0 0 NULL
.... Like till Dec
You should create a virtual table or subquery for the months, and left join it to the totals query.
eg
select * from
(
select number, datename(m,DATEADD(m, number-1, 0)) as monthname
from master..spt_values
where type='p' and number between 1 and 12
) months
left join
(your totals query) totals
on months.monthname = totals.month
try this:
;with cte as(
select 1 as rn union all select 2 union all select 3),
cte1 as (select ROW_NUMBER() over(order by c1.rn) as row_num
from cte cross join cte c1 cross join cte c2)
select * from cte1
left join
(SELECT DATENAME(mm, date) [Month],
sum(braekTime) [TotalBreakTime],
sum(DATEPART(hh,totalTime) * 60 + DATEPART(mi,totalTime) + DATEPART(ss,totalTime) * 0.017) [Minute],
firstName
FROM employeeAttendance join employee
on FK_employeeId = employee.employeeId
GROUP BY DATENAME(mm, date),firstName
ORDER BY [Month])B
on B.[Month]=DateName( month , DateAdd( month ,cte1.row_num , 0 ) - 1 )
and cte1.row_num <=12

How to query Open-high-low-close (OHLC) data from SQL Server

I'm trying to retrieve data for a Open-high-low-close (OHLC) chart directly from the database, it's the kind of chart you see of stocks. Is this possible, and if, how?
I have a table like this (simplified):
Date | Price | PriceType
A record is created for each day, I will report per month / year, not per day as used for stocks.
I would like to query something like this:
SELECT PriceType, MAX(Price) as High, MIN(Price) as Low, [Price of first item of month] as Open, [Price of last item of month] as Close GROUP BY PriceType, Year(Date), Month(Date)
To access the SQL Server I use LLBLGen, so an anwser based on that technology would be great, a generic SQL server will do too!
It's SQL 2005, but 2008 is also an option.
Thanks.
This appears to work. There may well be a less verbose way to do it.
--create test data
CREATE TABLE #t
(priceDate DATETIME
,price MONEY
,priceType CHAR(1)
)
INSERT #t
SELECT '20090101',100,'A'
UNION SELECT '20090102',500,'A'
UNION SELECT '20090103',20 ,'A'
UNION SELECT '20090104',25 ,'A'
UNION SELECT '20090105',28 ,'A'
UNION SELECT '20090131',150,'A'
UNION SELECT '20090201',501,'A'
UNION SELECT '20090203',21 ,'A'
UNION SELECT '20090204',26 ,'A'
UNION SELECT '20090205',29 ,'A'
UNION SELECT '20090228',151,'A'
UNION SELECT '20090101',100,'B'
UNION SELECT '20090102',500,'B'
UNION SELECT '20090103',20 ,'B'
UNION SELECT '20090104',25 ,'B'
UNION SELECT '20090105',28 ,'B'
UNION SELECT '20090131',150,'B'
UNION SELECT '20090201',501,'B'
UNION SELECT '20090203',21 ,'B'
UNION SELECT '20090204',26 ,'B'
UNION SELECT '20090205',29 ,'B'
UNION SELECT '20090228',151,'B'
--query
;WITH rangeCTE
AS
(
SELECT MIN(priceDate) minDate
,MAX(priceDate) maxDate
FROM #t
)
,datelistCTE
AS
(
SELECT CAST(CONVERT(CHAR(6),minDate,112) + '01' AS DATETIME) AS monthStart
,DATEADD(mm,1,CAST(CONVERT(CHAR(6),minDate,112) + '01' AS DATETIME)) -1 AS monthEnd
,1 AS monthID
FROM rangeCTE
UNION ALL
SELECT DATEADD(mm,1,monthStart)
,DATEADD(mm,2,monthStart) - 1
,monthID + 1
FROM datelistCTE
WHERE monthStart <= (SELECT maxDate FROM rangeCTE)
)
,priceOrderCTE
AS
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
ORDER BY priceDate
) AS rn1
,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
ORDER BY priceDate DESC
) AS rn2
,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
ORDER BY price DESC
) AS rn3
,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
ORDER BY price
) AS rn4
FROM datelistCTE AS d
JOIN #t AS t
ON t.priceDate BETWEEN d.monthStart AND d.monthEnd
WHERE monthStart <= (SELECT maxDate FROM rangeCTE)
)
SELECT o.MonthStart
,o.priceType
,o.Price AS opening
,c.price AS closing
,h.price AS high
,l.price AS low
FROM priceOrderCTE AS o
JOIN priceOrderCTE AS c
ON c.priceType = o.PriceType
AND c.monthID = o.MonthID
JOIN priceOrderCTE AS h
ON h.priceType = o.PriceType
AND h.monthID = o.MonthID
JOIN priceOrderCTE AS l
ON l.priceType = o.PriceType
AND l.monthID = o.MonthID
WHERE o.rn1 = 1
AND c.rn2 = 1
AND h.rn3 = 1
AND l.rn4 = 1
This is a little query I wrote that seems to work nicely for one time span at a time. All you need to do is comment the select DATEPARTS in order to get to the timespan you are looking for. Or you could just make multiple views for different timespans. Also the underlying data table uses Bid Ask tick style data. If you are using mids or last prices you could eliminate the case statements from the selects.
Select
tmp.num,
rf.CurveName,
rf.Period as Period,
CASE WHEN (tmp2.Bid is null or tmp2.Ask is null) then isnull(tmp2.Bid,0)+isnull(tmp2.Ask,0) else (tmp2.Bid+tmp2.Ask)/2 end as [Open],
tmp.Hi,
tmp.Lo,
CASE WHEN (rf.Bid is null or Rf.Ask is null) then isnull(rf.Bid,0)+isnull(rf.Ask,0) else (rf.Bid+rf.Ask)/2 end as [Close],
tmp.OpenDate,
tmp.CloseDate,
tmp.yr,
tmp.mth,
tmp.wk,
tmp.dy,
tmp.hr
from BidAsk rf inner join
(SELECT count(CurveName)as num,CurveName,
Period,
max(CASE WHEN (Bid is null or Ask is null) then isnull(Bid,0)+isnull(Ask,0) else (Bid+Ask)/2 end) as Hi,
min(CASE WHEN (Bid is null or Ask is null) then isnull(Bid,0)+isnull(Ask,0) else (Bid+Ask)/2 end) as Lo,
max(CurveDateTime) as CloseDate, min(CurveDateTime) as OpenDate,
DATEPART(year, CurveDateTime) As yr,
DATEPART(month, CurveDateTime) As mth,
DATEPART(week, CurveDateTime) As wk,
DATEPART(Day, CurveDateTime) as dy,
DATEPART(Hour, CurveDateTime) as hr
--DATEPART(minute, CurveDateTime) as mnt
FROM
BidAsk
GROUP BY
CurveName,Period,
DATEPART(year, CurveDateTime),
DATEPART(month, CurveDateTime),
DATEPART(week, CurveDateTime),
DATEPART(Day, CurveDateTime) ,
DATEPART(Hour, CurveDateTime)
--DATEPART(minute, CurveDateTime)
) tmp on
tmp.CurveName=rf.CurveName and
tmp.CloseDate=rf.CurveDateTime and
tmp.Period=rf.Period
inner join BidAsk tmp2 on
tmp2.CurveName=rf.CurveName and
tmp2.CurveDateTime=tmp.Opendate and
tmp2.Period=rf.Period
ORDER BY
CurveName,Period,tmp.yr,tmp.mth
--DATEPART(year, CurveDateTime),
--DATEPART(month, CurveDateTime)
--DATEPART(day, CurveDateTime),
--DATEPART(Hour, CurveDateTime),
--DATEPART(minute, CurveDateTime) )

Resources