conditional select with time adding calculation - sql

I have this table:
id | PlateNumber | ImgDate | ImgTime|
1 | abc123 | 2020-03-01 | 09:10:33|
2 | qwe128 | 2020-03-02| 09:13:39|
3 | abc123 | 2020-03-01| 09:11:21|
So, there are too many repeated plate numbers based on image capturing time.
I need a select statement that returns repeated records only when there is a time difference of more than 3 minutes. I hope that this makes sense.
Please help
Thank you guys!

You need to provide a bit more info, but you would want to compare the current row with the previous one (for each PlateNumber). You can do that using an analytical function like LAG.
WITH CTE as (
Select
id
,PlateNumber
,ImgDate
,ImgTime
,LAG(ImgDate) OVER (PARTITION BY PlateNumber ORDER BY ImgDate,ImgTime) as PreviousDate
,LAG(ImgTime) OVER (PARTITION BY PlateNumber ORDER BY ImgDate,ImgTime) as PreviousImgTime
FROM YourTable
)
Select id
,PlateNumber
,ImgDate
,ImgTime
FROM CTE
WHERE (PreviousDate is null and PreviousImgTime is null) -- to keep the first occurence
OR (
DATEDIFF(second,
DATEADD(day, 0, DATEDIFF(day, 0, PreviousDate)) + DATEADD(day, 0 - DATEDIFF(day, 0, PreviousImgTime), PreviousImgTime) ,
DATEADD(day, 0, DATEDIFF(day, 0, ImgDate)) + DATEADD(day, 0 - DATEDIFF(day, 0, ImgTime), ImgTime)
) > 180
)
If your columns are DATE and TIME datatype
OR (
DATEDIFF(second,
cast(PreviousDate as DATETIME) +cast(PreviousImgTime as DATETIME) ,
cast(ImgDate as DATETIME) + cast(ImgTime as DATETIME),
) > 180
)

In SQL Server, you can add datetime values, so you can do this basically just with lag():
select t.*
from (select t.*, v.dt,
lag(dt) over (partition by platenumber order by dt) as prev_dt
from t cross apply
(values (convert(datetime, t.imgdate) + convert(datetime, t.imgtime))
) as v(dt)
) t
where prev_dt is null or prev_dt < dateadd(minute, -3, dt);

Related

SQL Finding Missing Dates Between Ranges

I have a table of jobs that have ran for different source systems. These have a "RunDate" and then the FromDate and ToDate.
I want to find the gaps where we are missing any dates in the FromDate and ToDate fields to make sure that we have covered the data in those periods.
Many examples I've looked at work where a single date misses in a single column of ranges, however I have a From and To range that I need to test and ultimately work out where a date may be missed.
CREATE TABLE #temptable ( [SourceSystem] nchar(3), [RunDate] datetime, [ResubmitCount] int, [FromDate] date, [ToDate] date )
INSERT INTO #temptable
VALUES
( N'ILG', N'2021-07-28T15:35:23.207', 0, N'2021-06-01T00:00:00', N'2021-06-01T00:00:00' ),
( N'ILG', N'2021-07-28T15:35:23.707', 0, N'2021-06-05T00:00:00', N'2021-06-06T00:00:00' ),
( N'AAP', N'2021-07-28T15:35:23.833', 0, N'2021-06-01T00:00:00', N'2021-06-02T00:00:00' ),
( N'AAP', N'2021-07-28T15:35:23.833', 0, N'2021-06-04T00:00:00', N'2021-06-04T00:00:00' ),
( N'ZZP', N'2021-07-28T15:35:23.897', 0, N'2021-06-05T00:00:00', N'2021-06-05T00:00:00' )
DROP TABLE #temptable
So obviously using the example above I should be able to ascertain that the period between 2021-06-02 and 2021-06-04 for SourceSystem ILG and period 2021-06-03 to 2021-06-03 is missing for SourceSystem AAP.
Struggling to make it work for ranges, I can work with single dates but the system doesn't log them in this fasion.
UPDATE
I took the accepted answer and then tagged some code to it to be able to explode all the individual dates between the ranges specified.
Included the code in case anyone needs in the future.
WITH
a AS (
SELECT
SourceSystem, FromDate, ToDate,
LEAD(FromDate) OVER(
PARTITION BY SourceSystem
ORDER BY RunDate
) AS NextDate
FROM dbo.WDSubmission ws
),
gap_periods AS
(
SELECT
SourceSystem,
DATEADD(DAY, 1, ToDate) AS GapBeg,
DATEADD(DAY, -1, NextDate) AS GapFin
FROM a
WHERE
NextDate IS NOT NULL AND
DATEADD(DAY, -2, NextDate) >= ToDate
--AND a.SourceSystem = 'OGI'
) , E00(N) AS (SELECT 1 UNION ALL SELECT 1)
,E02(N) AS (SELECT 1 FROM E00 a, E00 b)
,E04(N) AS (SELECT 1 FROM E02 a, E02 b)
,E08(N) AS (SELECT 1 FROM E04 a, E04 b)
,E16(N) AS (SELECT 1 FROM E08 a, E08 b)
,E32(N) AS (SELECT 1 FROM E16 a, E16 b)
,cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E32)
,DateRange AS
(
SELECT ExplodedDate = DATEADD(DAY,N - 1,'2021-01-01')
FROM cteTally
WHERE N <= DATEDIFF(DAY,'2021-01-01',GETDATE())
)
SELECT *
FROM gap_periods eh
JOIN DateRange d ON d.ExplodedDate >= eh.GapBeg
AND d.ExplodedDate <= eh.GapFin;
Try this:
WITH
a AS (
SELECT
SourceSystem, FromDate, ToDate,
LEAD(FromDate) OVER(
PARTITION BY SourceSystem
ORDER BY RunDate
) AS NextDate
FROM #temptable
)
SELECT
SourceSystem,
DATEADD(DAY, 1, ToDate) AS GapBeg,
DATEADD(DAY, -1, NextDate) AS GapFin
FROM a
WHERE
NextDate IS NOT NULL AND
DATEADD(DAY, -2, NextDate) >= ToDate;
Result:
+--------------+------------+------------+
| SourceSystem | GapBeg | GapFin |
+--------------+------------+------------+
| AAP | 2021-06-03 | 2021-06-03 |
| ILG | 2021-06-02 | 2021-06-04 |
+--------------+------------+------------+
db-fiddle
Its hard to display the missing dates and also it would be too much information to analyze. Bbut you can get the number of days skipped in between using the below query :
select *,datediff(day,lag(ToDate)over(partition by sourcesystem order by ToDate),fromdate) from #temptable
The data would look something like this (last column tells the number of days skipped) :

How to find latest record by each day - kind of like a running status by day

I have a ResourceStatusHist table which records the status of resources whenever they change:
create table ResourceStatusHist
(
ResourceStatusHistId INT IDENTITY(1,1) NOT NULL,
ActionDateTime DateTime NOT NULL,
ResourceId INT NOT NULL,
Status varchar(50)
);
GO
INSERT INTO ResourceStatusHist
VALUES
('2020-01-24 13:00:00', 1, 'Active'),
('2020-01-21 09:12:00', 1, 'Offline'),
('2020-01-04 18:41:00', 1, 'Active')
;
Now I want to list the status of each resource at the end of each day over the last 5 days. It should look like this:
Day ResourceId Status
------------------------------------
2020-01-24 1 Active
2020-01-23 1 Offline
2020-01-22 1 Offline
2020-01-21 1 Offline
2020-01-20 1 Active
So far, I have got it to work by running separate insert statements for each day. So, for past 5 days, I have 5 insert statements. I am guessing there is a more efficient way of doing this.
You want a list of the days. Then apply or a correlated subquery does what you want:
select rsh.*
from (values (convert(date, getdate())),
(dateadd(day, -1, convert(date, getdate()))),
(dateadd(day, -2, convert(date, getdate()))),
(dateadd(day, -3, convert(date, getdate()))),
(dateadd(day, -4, convert(date, getdate())))
) v(dte) cross join
resources r outer apply
(select top (1) rsh.*
from ResourceStatusHist rsh
where rsh.ResourceId = r.ResourceId and
rsh.ActionDateTime < dateadd(day, 1, v.dte)
order by rsh.ActionDateTime desc
) rsh
Note: This is assuming that there is a table resources that has the resource ids. You can replace this with (select distinct resourceid from ResourceStatusHist) if such a table is not available.
If I understood correctly, there will be multiple records each day flipping the status field back and forth and you're trying to capture what the status was at the end of the day based on the ActionDateTime field.
The following will group the history by the day of ActionDateTime and take the top record ordered by ActionDateTime DESC (most recent at top) by using ROW_NUMBER() OVER (PARTITION ...):
SELECT CONVERT(DATE, ActionDateTime) as 'Day', ResourceId, Status
FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY CONVERT(DATE, ActionDateTime)
ORDER BY ActionDateTime DESC) as 'rn'
FROM ResourceStatusHist ) t
WHERE rn = 1
Here is a SqlFiddle for a working example.

SQL how to write a query that return missing date ranges?

I am trying to figure out how to write a query that looks at certain records and finds missing date ranges between today and 9999-12-31.
My data looks like below:
ID |start_dt |end_dt |prc_or_disc_1
10412 |2018-07-17 00:00:00.000 |2018-07-20 00:00:00.000 |1050.000000
10413 |2018-07-23 00:00:00.000 |2018-07-26 00:00:00.000 |1040.000000
So for this data I would want my query to return:
2018-07-10 | 2018-07-16
2018-07-21 | 2018-07-22
2018-07-27 | 9999-12-31
I'm not really sure where to start. Is this possible?
You can do that using the lag() function in MS SQL (but that is available starting with 2012?).
with myData as
(
select *,
lag(end_dt,1) over (order by start_dt) as lagEnd
from myTable),
myMax as
(
select Max(end_dt) as maxDate from myTable
)
select dateadd(d,1,lagEnd) as StartDate, dateadd(d, -1, start_dt) as EndDate
from myData
where lagEnd is not null and dateadd(d,1,lagEnd) < start_dt
union all
select dateAdd(d,1,maxDate) as StartDate, cast('99991231' as Datetime) as EndDate
from myMax
where maxDate < '99991231';
If lag() is not available in MS SQL 2008, then you can mimic it with row_number() and joining.
select
CASE WHEN DATEDIFF(day, end_dt, ISNULL(LEAD(start_dt) over (order by ID), '99991231')) > 1 then end_dt +1 END as F1,
CASE WHEN DATEDIFF(day, end_dt, ISNULL(LEAD(start_dt) over (order by ID), '99991231')) > 1 then ISNULL(LEAD(start_dt) over (order by ID) - 1, '99991231') END as F2
from t
Working SQLFiddle example is -> Here
FOR 2008 VERSION
SELECT
X.end_dt + 1 as F1,
ISNULL(Y.start_dt-1, '99991231') as F2
FROM t X
LEFT JOIN (
SELECT
*
, (SELECT MAX(ID) FROM t WHERE ID < A.ID) as ID2
FROM t A) Y ON X.ID = Y.ID2
WHERE DATEDIFF(day, X.end_dt, ISNULL(Y.start_dt, '99991231')) > 1
Working SQLFiddle example is -> Here
This should work in 2008, it assumes that ranges in your table do not overlap. It will also eliminate rows where the end_date of the current row is a day before the start date of the next row.
with dtRanges as (
select start_dt, end_dt, row_number() over (order by start_dt) as rownum
from table1
)
select t2.end_dt + 1, coalesce(start_dt_next -1,'99991231')
FROM
( select dr1.start_dt, dr1.end_dt,dr2.start_dt as start_dt_next
from dtRanges dr1
left join dtRanges dr2 on dr2.rownum = dr1.rownum + 1
) t2
where
t2.end_dt + 1 <> coalesce(start_dt_next,'99991231')
http://sqlfiddle.com/#!18/65238/1
SELECT
*
FROM
(
SELECT
end_dt+1 AS start_dt,
LEAD(start_dt-1, 1, '9999-12-31')
OVER (ORDER BY start_dt)
AS end_dt
FROM
yourTable
)
gaps
WHERE
gaps.end_dt >= gaps.start_dt
I would, however, strongly urge you to use end dates that are "exclusive". That is, the range is everything up to but excluding the end_dt.
That way, a range of one day becomes '2018-07-09', '2018-07-10'.
It's really clear that my range is one day long, if you subtract one from the other you get a day.
Also, if you ever change to needing hour granularity or minute granularity you don't need to change your data. It just works. Always. Reliably. Intuitively.
If you search the web you'll find plenty of documentation on why inclusive-start and exclusive-end is a very good idea from a software perspective. (Then, in the query above, you can remove the wonky +1 and -1.)
This solves your case, but provide some sample data if there will ever be overlaps, fringe cases, etc.
Take one day after your end date and 1 day before the next line's start date.
DECLARE # TABLE (ID int, start_dt DATETIME, end_dt DATETIME, prc VARCHAR(100))
INSERT INTO # (id, start_dt, end_dt, prc)
VALUES
(10410, '2018-07-09 00:00:00.00','2018-07-12 00:00:00.000','1025.000000'),
(10412, '2018-07-17 00:00:00.00','2018-07-20 00:00:00.000','1050.000000'),
(10413, '2018-07-23 00:00:00.00','2018-07-26 00:00:00.000','1040.000000')
SELECT DATEADD(DAY, 1, end_dt)
, DATEADD(DAY, -1, LEAD(start_dt, 1, '9999-12-31') OVER(ORDER BY id) )
FROM #
You may want to take a look at this:
http://sqlfiddle.com/#!18/3a224/1
You just have to edit the begin range to today and the end range to 9999-12-31.

Query to get results for every hour of the day even data if not present

I am trying to get the query for getting the count of users every hour of day in the table. If the data for that hour is not present, I want to record the hour with count of zero. Also users should be counted only for their first entry. Subsequent entries should be ignored.
Table:
userId creationDate
1 2014-10-08 14:33:20.763
2 2014-10-09 04:24:14.283
3 2014-10-10 18:34:26.260
Desired output:
Date UserCount
2014-10-08 00:00:00.000 1
2014-10-08 01:00:00.000 1
2014-10-08 02:00:00.000 1
2014-10-08 03:00:00.000 0
2014-10-08 04:00:00.000 1
....
.....
2014-10-10 23:00:00.000 1
2014-10-10 00:00:00.000 0
My attempt:
SELECT
CAST(creationDate as date) AS ForDate,
DATEPART(hour, date) AS OnHour,
COUNT(distinct userId) AS Totals
FROM
Table
WHERE
primaryKey = 123
GROUP BY
CAST(creationDate as date), DATEPART(hour, createDate)
This only gives me per hour for the record that is present. Not the data for the missing hours. I think there is a way by using a cross join to get 0 data even for the missing hours.
Something like this, I came across, but not able to construct a proper query with it.
cross join (select
ROW_NUMBER() over (order by (select NULL)) as seqnum
from
INFORMATION_SCHEMA.COLUMNS) hours
where hours.seqnum >= 24
Once again, I am not a SQL expert, but trying hard to construct this result set.
One more attempt :
with dh as (
select DATEADD(hour, seqnum - 1, thedatehour ) as DateHour
from (select distinct cast(cast(createDate as DATE) as datetime) as thedatehour
from Table a
) a
cross join
(select ROW_NUMBER() over (order by (select NULL)) as seqnum
from INFORMATION_SCHEMA.COLUMNS
) hours
where hours.seqnum (less than)= 24
)
select dh.DateHour, COUNT(distinct c.userId)
from dh cross join Table c
--on dh.DateHour = c.createDate
group by dh.DateHour
order by 1
You need to build up a table of possible hours, and then join this to your actual records.
The best way to build up a table of possible hours is to use a recursive common table expression.
Here's how:
-- Example data
DECLARE #users TABLE(UserID INT, creationDate DATETIME)
INSERT #users
( UserID, creationDate )
VALUES ( 1, '2014-10-08 14:33:20.763'),
( 2, '2014-10-09 04:24:14.283'),
( 3, '2014-10-10 18:34:26.260')
;WITH u1st AS ( -- determine the FIRST time the user appears
SELECT UserID, MIN(creationDate) AS creationDate
FROM #users
GROUP BY UserID
), hrs AS ( -- recursive CTE of start hours
SELECT DISTINCT CAST(CAST(creationDate AS DATE) AS DATETIME) AS [StartHour]
FROM #users AS u
UNION ALL
SELECT DATEADD(HOUR, 1, [StartHour]) AS [StartHour] FROM hrs
WHERE DATEPART(HOUR,[StartHour]) < 23
), uGrp AS ( -- your data grouped by start hour
SELECT -- note that DATETIMEFROMPARTS is only in SQL Server 2012 and later
DATETIMEFROMPARTS(YEAR(CreationDate),MONTH(CreationDate),
DAY(creationDate),DATEPART(HOUR, creationDate),0,0,0)
AS StartHour,
COUNT(1) AS UserCount FROM u1st AS u
GROUP BY YEAR(creationDate), MONTH(creationDate), DAY(creationDate),
DATEPART(HOUR, creationDate)
)
SELECT hrs.StartHour, ISNULL(uGrp.UserCount, 0) AS UserCount
FROM hrs LEFT JOIN uGrp ON hrs.StartHour = uGrp.StartHour
ORDER BY hrs.StartHour
NB - DATETIMEFROMPARTS is only in SQL SERVER 2012 and greater. If you are using an earlier version of SQL SERVER you could have
WITH u1st AS ( -- determine the FIRST time the user appears
SELECT UserID, MIN(creationDate) AS creationDate
FROM #users
GROUP BY UserID
), hrs AS ( -- recursive CTE of start hours
SELECT DISTINCT CAST(CAST(creationDate AS DATE) AS DATETIME) AS [StartHour]
FROM #users AS u
UNION ALL
SELECT DATEADD(HOUR, 1, [StartHour]) AS [StartHour] FROM hrs
WHERE DATEPART(HOUR,[StartHour]) < 23
), uGrp AS ( -- your data grouped by start hour
SELECT -- note that DATETIMEFROMPARTS is only in SQL Server 2012 and later
CAST(CAST(YEAR(creationDate) AS CHAR(4)) + '-'
+ RIGHT('0' + CAST(MONTH(creationDate) AS CHAR(2)), 2) + '-'
+ RIGHT('0' + CAST(DAY(creationDate) AS CHAR(2)), 2) + ' '
+ RIGHT('0' + CAST(DATEPART(HOUR, creationDate) AS CHAR(2)), 2)
+ ':00:00.000'
AS DATETIME) AS StartHour,
COUNT(1) AS UserCount FROM u1st AS u
GROUP BY YEAR(creationDate), MONTH(creationDate), DAY(creationDate),
DATEPART(HOUR,creationDate)
)
SELECT hrs.StartHour, ISNULL(uGrp.UserCount, 0) AS UserCount
FROM hrs LEFT JOIN uGrp ON hrs.StartHour = uGrp.StartHour
ORDER BY hrs.StartHour
I asked a similar question on dba just this morning...https://dba.stackexchange.com/questions/86435/filling-in-date-holes-in-grouped-by-date-sql-data.
You can used my GetSequence function, or create a Numbers table. I haven't done my own testing yet to validate what was suggested in my scenario.
Try this:
BUILD SAMPLE DATA
CREATE TABLE yourTable(
userId INT,
creationDate DATETIME
)
INSERT INTO yourTable VALUES (1, '2014-10-08 14:33:20.763'), (2, '2014-10-09 04:24:14.283'),(3, '2014-10-10 18:34:26.260');
SOLUTION
WITH tally(N) AS(
SELECT TOP(23) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM sys.columns
)
,hourly(creationDate) AS(
SELECT DATEADD(HOUR, t.N, d.creationDate)
FROM tally t
CROSS JOIN(
SELECT DISTINCT DATEADD(DD, DATEDIFF(DD, 0, creationDate), 0) AS creationDate FROM yourTable
) d
)
SELECT
h.creationDate,
userCount = ISNULL(t.userCount, 0)
FROM hourly h
LEFT JOIN(
SELECT
creationDate = DATEADD(HOUR, DATEPART(HOUR, creationDate) ,DATEADD(DD, DATEDIFF(DD, 0, creationDate), 0)),
userCount = COUNT(*)
FROM yourTable
GROUP BY DATEADD(DD, DATEDIFF(DD, 0, creationDate), 0), DATEPART(HOUR, creationDate)
)t
ON t.creationDate = h.creationDate
CLEANUP
DROP TABLE yourTable
Create a temporary table (let's say #CreationDateHours) containing create date and hours from 0 to 23.
Declare #date as date
SELECT MAX(CAST(creationDate as date)) AS ForDate, 0 as OnHour into #CreationDateHours
FROM Table
WHERE
primaryKey = 123
Select #date=ForDate from #CreationDateHours
Declare #i int
Set #i=1
While #i<24
begin
insert into #CreationDateHours
select #date as ForDate, #i as OnHour
set #i+=1
end
Now, Run this query to get the desired results
select t1.ForDate, t1.OnHour, isnull(t2.Totals,0) AS Totals
from
#CreationDateHours t1 left join (SELECT
CAST(creationDate as date) AS ForDate,
DATEPART(hour, date) AS OnHour,
COUNT(distinct userId) AS Totals
FROM
Table
WHERE
primaryKey = 123
GROUP BY
CAST(creationDate as date), DATEPART(hour, createDate)) as t2
on t1.ForDate= t2.ForDate and t1.OnHour=t2.OnHour
select count, strftime('%H', creationDate) as hour from table group by hour;
OUTUPUT:
count hour
n1 01
n2 02
n3 03
... ...
n24 24
Tested on SQLite3
https://www.sqlite.org/lang_datefunc.html
you can see all the formats
(like %d for every day of month)
if you want the whole date
strftime('%Y-%m-%d %H, creationDate)

Create a weekCount column in SQL Server 2012

I have this data:
id worked_date
-----------------
1 2013-09-25
2 2013-09-26
3 2013-10-01
4 2013-10-04
5 2013-10-07
I want to add a column called weekCount. The based date is 2013-09-25. So all the data with worked_date from 2013-09-25 to 2013-10-01 will have weekCount as 1 and from 2013-10-02 to 2013-10-8 will have weekCount as 2 and so on. How can that be done?
Thanks.
Here's one way using DATEDIFF:
select id,
worked_date,
1 + (datediff(day, '2013-09-25', worked_date) / 7) weekCount
from yourtable
SQL Fiddle Demo
Perhaps an approach like this will solve your problem.
I compute an in-memory table that contains the week's boundaries along with a monotonically increasing number (BuildWeeks). I then compare my worked_date values to my date boundaries. Based on your comment to #sgeddes, you need the reverse week number so I then use a DENSE_RANK function to calculate the ReverseWeekNumber.
WITH BOT(StartDate) AS
(
SELECT CAST('2013-09-25' AS date)
)
, BuildWeeks (WeekNumber, StartOfWeek, EndOfWeek) AS
(
SELECT
N.number AS WeekNumber
, DateAdd(week, N.number -1, B.StartDate) AS StartOfWeek
, DateAdd(d, -1, DateAdd(week, N.number, B.StartDate)) AS EndOfWeek
FROM
dbo.Numbers AS N
CROSS APPLY
BOT AS B
)
SELECT
M.*
, BW.*
, DENSE_RANK() OVER (ORDER BY BW.WeekNumber DESC) AS ReverseWeekNumber
FROM
dbo.MyTable M
INNER JOIN
BuildWeeks AS BW
ON M.worked_date BETWEEN BW.StartOfWeek ANd BW.EndOfWeek
;
SQLFiddle
If you are looking for a Fiscal Week number, I would use a function that would calculate the week:
CREATE FUNCTION FiscalWeek(#FiscalStartDate datetime, #EvalDate datetime)
RETURNS INT
AS
BEGIN
DECLARE #weekNumber INT = (DATEDIFF(DAY, #FiscalStartDate, #EvalDate) / 7) + 1
RETURN (#weekNumber % 52)
END
GO
If you used a fiscal starting date of '2013-09-25' and an evaluation date of '2014-09-25' you would get a week number of 1.
Using a function gives you a little more flexibility to do whatever you need.
Perhaps not the most elegant way but this works for me to get the top rank number:
WITH CTE AS (
SELECT employee_id, DENSE_RANK() OVER (ORDER BY DATEDIFF(DAY, ''20130925'', worked_date )/7 DESC) AS weekRank
FROM Timesheet
)
SELECT TOP (1) weekRank
FROM CTE
WHERE employee_id=#employee_id
ORDER BY weekRank DESC
This is how I can create weekRank column and pass a parameter dynamically:
WITH rank_cte AS (
SELECT timesheet_id,employee_id, date_worked,
dateadd(week, datediff(day,'20000105',worked_date) / 7, '20000105') AS WeekStart,
dateadd(week, datediff(day,'20000105',worked_date) / 7, '20000105')+6 AS WeekEnd,
DENSE_RANK() OVER (ORDER BY 1 + DATEDIFF(DAY, '20130925', worked_date )/7 DESC) AS weekRank
FROM Timesheet
)
SELECT timesheet_id, worked_date, WeekStart, WeekEnd, weekRank
FROM rank_cte rc
WHERE employee_id=#employee_id
AND weekRank=#weekRank
ORDER BY worked_date DESC
Thanks