i need a sql function which has to return 5th previous business date except saturday sunday and public holiday,
Ex: i should get last thursday (04-01-2018) if i won't have any public holiday inbetween im able to achieve that by,
SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 5, GETDATE()))
but how to omit public holiday from this,
Can anyone help me please
If you don't want (or you can't) create a calendar "tally" table (with columns identifying holidays and week-end days) you can try a query like following one.
sample data for holidays table
CREATE TABLE HOL_TAB (DAT DATETIME);
INSERT INTO HOL_TAB VALUES ('2018-01-05');
INSERT INTO HOL_TAB VALUES ('2018-01-04');
The query use a CTE to "create" on the fly a small tally calendar table (I used 12 as limit, but you can change it).
The last SELECT use a join with holiday table to exclude those days and then ROW_NUMBER() to extract "first" five days.
To keep query similar to the one you made I used DATENAME, but I suggest to avoid its use and use instead other methods).
WITH CAL_TAB AS (
SELECT DATEADD(dd, 0, CAST(GETDATE() AS DATE) ) AS DAT
, 1 AS COUN
UNION ALL
SELECT DATEADD(dd, -1- CASE DATENAME (WEEKDAY, DATEADD(dd,-1,B.DAT) ) WHEN 'Sunday' THEN 2 WHEN 'Saturday' THEN 1 ELSE 0 END, B.DAT ) AS DAT
, B.COUN+1 AS COUN
FROM CAL_TAB B
WHERE B.COUN<12 /* 12 is just to limit number of days */
)
SELECT DAT, WD
FROM (SELECT C.DAT, C.COUN, DATENAME(WEEKDAY, C.DAT) AS WD, ROW_NUMBER() OVER (ORDER BY COUN) AS RN
FROM CAL_TAB C
WHERE NOT EXISTS(SELECT DAT FROM HOL_TAB D WHERE D.DAT=C.DAT)
) E WHERE RN<=5;
Output:
DAT WD
1 10.01.2018 00:00:00 Wednesday
2 09.01.2018 00:00:00 Tuesday
3 08.01.2018 00:00:00 Monday
4 03.01.2018 00:00:00 Wednesday
5 02.01.2018 00:00:00 Tuesday
try This Logic
WITH CTE
AS
(
SELECT
MyDate = DATEADD(DD,-5,GETDATE())
)
SELECT
MyDate = CASE WHEN DATENAME(WEEKDAY, MyDate) IN ('Sunday','Saturday')
THEN NULL
WHEN MHL.Holiday IS NOT NULL
THEN NULL
ELSE CTE.MyDate END
FROM CTE
LEFT JOIN MyHoliDayList MHL
ON CTE.MyDate = MHL.Holiday
Try this Method:
DECLARE #Holiday TABLE(HoliDay DATE)
INSERT INTO #Holiday VALUES ('2018-01-02')
INSERT INTO #Holiday VALUES ('2018-01-05')
DECLARE #WithOutHoliDay DATETIME = (SELECT DATEADD(DAY, CASE DATENAME(WEEKDAY, GETDATE())
WHEN 'Sunday' THEN -2
WHEN 'Monday' THEN -3
ELSE -1 END, DATEDIFF(DAY, 5, GETDATE())))
SELECT DATEADD(DAY,0-
(SELECT COUNT(1)
FROM #Holiday
WHERE HoliDay BETWEEN #WithOutHoliDay AND GETDATE()),#WithOutHoliDay)
This should give, what exactly you need...
Related
I have a table of Tasks where I have records for a particular date. I want to have all dates in one month displayed with numbers of tasks per date. If on some date there were no record of a task it should be written 0.
I have results with duplicating records from the same date when there were tasks on a given day.
Table:
Date Tasks
2021-08-01 0
2021-08-02 0
2021-08-03 0
2021-08-03 25
2021-08-04 0
2021-08-04 18
2021-08-05 0
2021-08-05 31
2021-08-06 0
SQL code I am using:
Declare #year int = 2021, #month int = 8;
WITH numbers
as
(
Select 1 as value
UNion ALL
Select value +1 from numbers
where value + 1 <= Day(EOMONTH(datefromparts(#year, #month, 1)))
)
SELECT datefromparts(#year, #month, numbers.value) AS 'Datum', 0 AS 'Tasks' FROM numbers
UNION
SELECT CONVERT(date, added_d) AS 'Datum', COUNT(*) AS 'Tasks' FROM Crm.Task
WHERE YEAR(added_d) = '2021' AND MONTH(added_d) = '8' GROUP BY CONVERT(date, added_d)
How can I remove duplicates that I will have only one date record 21-08-03 with 25 tasks?
Thank you for your help
You requires OUTER JOIN :
WITH numbers as (
Select datefromparts(#year, #month, 1) as value
UNION ALL
Select DATEADD(DAY, 1, value) as value
from numbers
where value < EOMONTH(value)
)
select num.value, COUNT(tsk.added_d) AS Tasks
from numbers num left join
Crm.Task tsk
on CONVERT(date, tsk.added_d) = num.value
GROUP BY num.value;
If you want all dates for one month, you can do:
with dates as (
select datefromparts(#year, #month, 1) as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < eomonth(dte)
)
You can then incorporate this into the logic using an outer join or subquery:
with dates as (
select datefromparts(#year, #month, 1) as dte
union all
select dateadd(day, 1, dte)
from dates
where dte < eomonth(dte)
)
select d.dte, count(t.added_d)
from dates d left join
Crm.Task t
on convert(date, t.added_d) = d.dte
group by d.dte
order by d.dte;
You can easily extend the logic for the CTE for more than one month, by adjusting the where clause in the second clause.
I'm having trouble to display the last 12 months for each record, can anyone help?
Right now I can only display one month for each record.
DECLARE #DateEnd as DATETIME = DATEADD(month,((YEAR(getdate())-1900)*12) + MONTH(getdate())-1,-1)
-- SET #DateEnd = '20191130'
DECLARE #Frequency_List table (FREQUENCY_ID char(3)); INSERT into #Frequency_List values ('118') -- ('111'),('118'),('110') -- 'MTD','QTD','YTD'
DECLARE #Entity_List table (ENTITY_NAME char(50)); INSERT into #Entity_List values
('F1000'),('R2202'),('R528'),('R810'),('R567'),('R402I'),('R508'),('F1000'),('A950A'),('R557'),('R559'),('R560'),('TBNOBL'),('ALTACORP'),('R590RVME'),('Z490'),('R5070'),('R591'),('R710')
select P.PORTF_CODE, F.EXT_NAME, REPLACE(CONVERT(VARCHAR(10), AKRE.BEGIN_DATE, 102), '.', '-') as 'BEGIN_DATE', REPLACE(CONVERT(VARCHAR(10), AKRE.END_DATE, 102), '.', '-') as 'END_DATE',
ISNULL(AKRE.PTF_END_OAD,0) 'PTF End Duration', ISNULL(AKRE.BMK_END_OAD,0) 'BMK End Duration', (ISNULL(AKRE.PTF_END_OAD,0)-ISNULL(AKRE.BMK_END_OAD,0)) 'Diff End Duration',
ISNULL(AKRE.PTF_END_OAS,0)*10000 'PTF End Spread', ISNULL(AKRE.BMK_END_OAS,0)*10000 'BMK End Spread', (ISNULL(AKRE.PTF_END_OAS,0)-ISNULL(AKRE.BMK_END_OAS,0))*10000 'Diff End Spread',
((ISNULL(AKRE.PTF_END_OAD,0)*(ISNULL(AKRE.PTF_END_OAS,0)*10000))-(ISNULL(AKRE.BMK_END_OAD,0)*(ISNULL(AKRE.BMK_END_OAS,0)*10000))) 'DIF_END_DTS'
from BISAMDW..ATTX_KEY_RATES_EFFECTS AKRE
left join BISAMDW..PORTFOLIO P on P.PORTF_ID = AKRE.PORTF_ID
left join BISAMDW..ATTR_INSTRUMENT AI on AI.ATINS_ID = AKRE.ATINS_ID
left join [BISAMDW].[dbo].[UD_GROUP] GRP on AKRE.USER_DEFINED_GROUP_ID=GRP.USER_DEFINED_GROUP_ID
left join BISAMDW..T_FREQUENCY F on F.FREQUENCY_ID = AKRE.FREQUENCY_ID
where AKRE.END_DATE = #DateEnd and P.PORTF_NAME in ( select ENTITY_NAME from #Entity_List)
and AKRE.PORTF_CONFIG_ID in ( 1 )
and AKRE.FREQUENCY_ID in (select FREQUENCY_ID from #Frequency_List)
and AKRE.PTF_RETURN is NOT null
and GRP.EXT_CODE in ('BARCLAYS','MASTER_2016')
order by 1,2
The result for the columns of start month and end month in sample resultshould be something like this:
MonthStartDate MonthEndDate
2011-04-01 2011-04-30
2011-05-01 2011-05-31
2011-06-01 2011-06-30
2011-07-01 2011-07-31
2011-08-01 2011-08-31
2011-09-01 2011-09-30
2011-10-01 2011-10-31
2011-11-01 2011-11-30
2011-12-01 2011-12-31
....
Thank you!
If what you want is generate a list of month starts and ends for the last 12 months (plus the current month), then one option is to use a recursive query:
with cte as (
select
dateadd(
year,
-1,
datefromparts(year(getdate()), month(getdate()), 1)
) monthStartDate
union all
select dateadd(month, 1, monthStartDate)
where monthStartDate < dateadd(month, -1, getdate())
)
select monthStartDate, eomonth(monthStartDate) monthEndDate from cte
If you are going to use this data several times, then you should store the results of this query in a separate table, which you can then use directly in your queries. This is called a calendar table.
Personally, I would suggest creating a Calendar Table (there are 100's of examples on how to create these), if you simply need the start and end dates of each month. Then getting the start and end dates from that table is trivial:
SELECT MIN(C.CalendarDate) AS MonthStart,
MAX(C.CalendarDate) AS MonthEnd
FROM dbo.Calendar C
WHERE C.CalendarDate >= '20110101'
AND C.CalendarDate < '20200601'
GROUP BY C.CalendarYear,
C.CalendarMonth;
Alternatively, you can use a Tally to generate these on the fly:
DECLARE #StartDate date = '20110101',
#EndDate date = '20200601';
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT TOP (SELECT DATEDIFF(MONTH, #StartDate, #EndDate)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
FROM N N1, N N2, N N3, N N4, N N5)
SELECT DATEADD(MONTH, T.I, #StartDate) AS MonthStart,
EOMONTH(DATEADD(MONTH, T.I, #StartDate)) AS MonthEnd
FROM Tally T;
I have a tricky issue I am struggling with on a mental level.
In our db we have a table showing the UK Holidays for the next few years, and a stored function returns a recordset to my front end.
I have a flag in my recordset called 'deletable' which allows the frontend to decide if a context menu can be shown in the data grid, thus allowing that record to be deleted.
Currently the test (in my stored proc) just checks if the date column has a date from three days ago or more.
case when DATEDIFF(d,a.[date],GETDATE()) > 3 then 1 else 0 end as [deletable]
how can I modify that to find the previous working date by checking weekends and the Holidays table 'Holiday' column (which is a Datetime) and see if the [date] column in my recordset row is 3 working days before, taking into account Holidays from the Holidays table and weekends?
so if the [date] column is 23th May, and todays's date is 28th May, then that column returns 0, as the 27th was a bank holiday, whereas the next day it would return 1 because there would be more than 3 working days difference.
Is there an elegent way to do that?
thanks
Philip
Okay I'm totally refactoring this.
declare
#DeletablePeriodStart datetime,
#BusinessDays int
set #DeletablePeriodStart = dateadd(d,0,datediff(d,0,getdate()))
set #BusinessDays = 0
while #BusinessDays < 3
begin
set #DeletablePeriodStart = dateadd(d,-1,#DeletablePeriodStart)
if datepart(dw,#DeletablePeriodStart) not in (1,7) and
not exists (select * from HolidayTable where Holiday = #DeletablePeriodStart)
begin
set #BusinessDays = #BusinessDays + 1
end
end
This time it doesn't make any assumptions. It runs a quick loop checking whether each day is a valid business day and doesn't stop till it counts three of them. Then later just check whether a.[date] >= #DeletablePeriodStart
You should substract the number of holidays between a.[date] and GETDATE() from the DATEDIFF. Try something like this:
case when DATEDIFF(d,a.[date],GETDATE())-(
SELECT COUNT(*) FROM Holidays
WHERE HolidayDate BETWEEN a.[date] AND GETDATE()
)>3 then 1 else 0 end as [deletable]
Razvan
I am assuming that you don't have a Calendar table, although I'd highly recommend creating one, you can still achieve this without one:
The following will just get you a list of 2047 dates from yesterday going backwards (using the system table Master..spt_values):
WITH Dates AS
( SELECT Date = DATEADD(DAY, -number, CAST(GETDATE() AS DATE))
FROM Master..spt_values
WHERE type = 'P'
AND number > 0
)
SELECT Dates.Date
FROM Dates
ORDER BY Dates.Date DESC;
You then need to exclude weekends, and holidays from your table using this:
SET DATEFIRST 1;
WITH Dates AS
( SELECT Date = DATEADD(DAY, -number, CAST(GETDATE() AS DATE))
FROM Master..spt_values
WHERE type = 'P'
AND number > 0
)
SELECT Dates.Date
FROM Dates
WHERE DATEPART(WEEKDAY, Dates.Date) <= 5
AND NOT EXISTS
( SELECT 1
FROM HolidayTable h
WHERE Dates.Date = h.HolidayDate
)
ORDER BY Dates.Date DESC;
N.B. You should explicitly set your DATEFIRST and not rely on server defaults
The above gives you a list of working days prior to today, you can then use the ROW_NUMBER() function, get the 3rd occurance in the list, giving a final query:
WITH Dates AS
( SELECT Date = DATEADD(DAY, -number, CAST(GETDATE() AS DATE))
FROM Master..spt_values
WHERE type = 'P'
AND number > 0
), WorkingDays AS
( SELECT Dates.Date, RN = ROW_NUMBER() OVER(ORDER BY Dates.Date DESC)
FROM Dates
WHERE DATEPART(WEEKDAY, Dates.Date) <= 5
AND NOT EXISTS
( SELECT 1
FROM HolidayTable h
WHERE Dates.Date = h.HolidayDate
)
)
SELECT WorkingDays.Date
FROM WorkingDays
WHERE RN = 3;
Or if you prefer this can be done with one query (exact same principle as above):
SELECT d.Date
FROM ( SELECT Date = DATEADD(DAY, -number, CAST(GETDATE() AS DATE)), RN = ROW_NUMBER() OVER(ORDER BY number)
FROM Master..spt_values
WHERE type = 'P'
AND number > 0
AND DATEPART(WEEKDAY, DATEADD(DAY, -number, CAST(GETDATE() AS DATE))) <= 5
AND NOT EXISTS
( SELECT 1
FROM HolidayTable h
WHERE DATEADD(DAY, -number, CAST(GETDATE() AS DATE)) = h.HolidayDate
)
) d
WHERE rn = 3;
I am looking for the number of Mon,Tues, Wed, Thur, Fri, Sat, Sun in the past 30 days. Can I select the last 30 days date and day of week without an actual database table? Something like
SELECT --everything between
convert(date,GETDATE()), DATENAME(DW, GETDATE())
--and
convert(date,GETDATE() - 30), DATENAME(DW, GETDATE())
You can use a recursive CTE:
;WITH CTE AS
(
SELECT convert(date,GETDATE()) sDate, DATENAME(DW, GETDATE()) sDayofWeek
UNION ALL
SELECT DATEADD(DAY,-1,sDate), DATENAME(DW, DATEADD(DAY,-1,sDate))
FROM CTE
WHERE sDate > GETDATE()-29
)
SELECT * FROM CTE
WITH cteCount AS (
SELECT DATENAME(dw, GETDATE()) dw, 1 ix
UNION ALL
SELECT DATENAME(dw, DATEADD(d, -ix, GETDATE())), ix+1 FROM cteCount WHERE ix<30
)
SELECT dw, COUNT(1) cnt FROM cteCount GROUP BY dw
A couple solutions:
SELECT ... From ... WHERE date > DATEADD(year, -1, GETDATE())
Also, I think this statement will work with MySQL:
select date_sub(now(),interval 30 day)as Datebefore30days;
Well, there are a couple of ways to do it.
You could fill a temp table, using a loop and INSERT statements, and then select the contents of the table. You could create a table-valued UDF to do this, in fact.
You could also create 30 SELECT statements, and UNION them all together. But, frankly, I think you're better off with option 1.
ETA: Thinking about it, if all you want is the number of each day of the week in the past 30 days, you can probably do that just with some math, without returning 30 records.
There are 4 instances of each day of the week in any 30 day period, plus 2 extra days. So all you really need is to know what day of the week the first day in your period is, and the second day. Those days of the week have 5 instances.
I'm pretty lazy and just load a temp table and then do a group by select on that temp table
DECLARE #tmpDates TABLE (calDate DATETIME)
DECLARE #beginDate DATETIME
SET #beginDate = DATEADD(day,-30,GETDATE())
WHILE #beginDate < GETDATE()
BEGIN
INSERT INTO #tmpDates ([calDate]) VALUES (#beginDate)
SET #beginDate = DATEADD(DAY,1,#beginDate)
END
SELECT DATEPART(dw,[calDate]) AS [weekDay], COUNT(1) AS [dayCount]
FROM #tmpDates
GROUP BY DATEPART(dw,[calDate])
Number of times each day of the week got hit in the last 30 days:
SELECT DATENAME(dw,GETDATE())+' 5 times' as results
UNION ALL
SELECT DATENAME(dw,DATEADD(day,-1,GETDATE()))+' 5 times'
UNION ALL
SELECT DATENAME(dw,DATEADD(day,-2,GETDATE()))+' 4 times'
UNION ALL
SELECT DATENAME(dw,DATEADD(day,-3,GETDATE()))+' 4 times'
UNION ALL
SELECT DATENAME(dw,DATEADD(day,-4,GETDATE()))+' 4 times'
UNION ALL
SELECT DATENAME(dw,DATEADD(day,-5,GETDATE()))+' 4 times'
UNION ALL
SELECT DATENAME(dw,DATEADD(day,-6,GETDATE()))+' 4 times'
This really is about dividing 30 by 7
This gives me
results
Thursday 5 times
Wednesday 5 times
Tuesday 4 times
Monday 4 times
Sunday 4 times
Saturday 4 times
Friday 4 times
I have a week number (e.g. 23) and I'd like to get the dates for Monday and Sunday of that week.
I am assuming Monday as the first day of the week (e.g. I have SET DATEFIRST 1 in my script).
DECLARE #startweek1 datetime
SET DATEFIRST 1
--first monday of year
SELECT #startweek1 = DATEADD(day, 8-DATEPART(weekday, '2011-01-01'), '2011-01-01')
--day based
SELECT
DATEADD(day, 22 * 7, #startweek1) AS MondayWeek23,
DATEADD(day, 23 * 7 -1 , #startweek1) AS SundayWeek23
--week based
SELECT
DATEADD(week, 22, #startweek1) AS MondayWeek23,
DATEADD(day, -1, DATEADD(week, 23 , #startweek1)) AS SundayWeek23
Edit:
This solution works if week 1 does not start on day 1 as Andomar said
Edit 2:
According to Wikipedia: 2008-12-29 is day 1 of week 1 of 2009 in ISO.
And week numbers vary as Andomar said
Cyberkiwi mentioned this code is wrong for 2007: it's wrong far more often than that. The same applies to his code too which matches 2007 but is equally wrong for the rest.
Declare #StartDate datetime;
Set #StartDate = '20110101';
With StartOfWeek As
(
Select DateAdd(
week
, 23
, DateAdd(
d
, -(DatePart(dw, #StartDate) - 1)
, #StartDate
) ) As Sunday
)
Select Sunday, DateAdd(d,1,Sunday) As Monday
From StartOfWeek
We can use the DATEFIRST variable to set the start day of the week. By default, the week starts on Sunday(7). In order to start with Monday, we will set its value to 1.
# Printing default value
Select ##DATEFIRST; -- This will give 7 value i.e. default value
# Changing first day of the week to Monday.
Declare #CurrentWeekNumber int
SET DATEFIRST 1
set #CurrentWeekNumber= (SELECT DATEPART(WEEK, GETDATE()))
select #CurrentWeekNumber
PS: Changes to DATEFIRST are valid for current session i.e. it doesn't impact other DB queries which might rely on different week start day.
A calendar table makes this kind of date query pretty simple. A calendar table just has the relevant calendar details calculated and stored at load time instead of calculated at run time. Depending on the application, that can speed things up a lot. This way is dbms agnostic; it just uses literals in the WHERE clause.
select cal_date from calendar
where iso_year = 2011
and iso_week = 23
and cal_dow in ('Mon', 'Sun');
And another way that relies only on having a table of dates.
select cal_date from calendar
where extract(isoyear from cal_date) = 2011
and extract(week from cal_date) = 23
and (extract(isodow from cal_date) = 1 or
extract(isodow from cal_date) = 7);
EXTRACT() is standard SQL, but I'm not sure whether the names of the subfields isoyear, week, isodow are standard SQL.
Note: Any answer that starts with assuming year is 2011 might as well take a static first date, i.e. by replacing #firstMon in my last query below with just the static date '20101227'.
SET DATEFIRST 1
declare #targetYear int
declare #targetWeek int
select #targetYear = 2011, #targetWeek = 23
declare #firstMon datetime
set #firstMon = dateadd(d,1-datepart(dw, right(#targetYear,4)+'0101'),right(#targetYear,4)+'0101')
select
MonOfTargetWeek = dateadd(week, #targetWeek-1, #firstMon),
SunOfTargetWeek = dateadd(week, #targetWeek-1, #firstMon+6)
And the real, final query - which returns a Mon/Sun of NULL when it doesn't exist in that week, such as Mon of partial-week-one or Sun of partial-week-53
;with tmp(Mon, Sun) as (
select
MonOfTargetWeek = dateadd(week, #targetWeek-1, #firstMon),
SunOfTargetWeek = dateadd(week, #targetWeek-1, #firstMon+6)
)
select
RealMonday = case when Year(Mon)=#targetYear then Mon end,
RealSunday = case when Year(Sun)=#targetYear then Sun end
from tmp
For GBN's claim that this answer is wrong (within his answer), I submit below the proof of correctness
I have turned the code into a function.
CREATE function dbo.getMonSunForWeek(#targetYear int, #targetWeek int)
returns table as return
with pre(firstMon) as (
select dateadd(d,1-datepart(dw, right(#targetYear,4)+'0101'),right(#targetYear,4)+'0101'))
, tmp(Mon, Sun) as (
select
dateadd(week, #targetWeek-1, firstMon),
dateadd(week, #targetWeek-1, firstMon+6)
from pre
)
select
Mon, Sun,
RealMonday = case when Year(Mon)=#targetYear then Mon end,
RealSunday = case when Year(Sun)=#targetYear then Sun end
from tmp
GO
And below I present the ENTIRE range of years and weeks (1-53) for the years from 1950 through 2047. In EVERY SINGLE case, when the Monday/Sunday has been determined, and working backwards using DATEPART(week), SQL Server agrees with the week numbering from the function.
set datefirst 1;
select
[Year] = years.number,
[Week] = weeks.number,
[Mon] = fun.realmonday,
[Sun] = fun.realsunday,
[WeekX] = isnull(datepart(week, fun.realmonday), datepart(week, fun.realsunday)),
[MonX] = fun.Mon,
[SunX] = fun.Sun
from master..spt_values years
inner join master..spt_values weeks on weeks.type='P' and weeks.number between 1 and 53
cross apply dbo.getMonSunForWeek(years.number, weeks.number) fun
where years.type='P' and years.number between 1950 and 2047
order by [year], [Week]
Output around the 2005-2006 changeover
when including prior/next year
Year Week Mon-of-week Sun-of-week datepart(week) Mon -and- Sun
2005 52 2005-12-19 2005-12-25 52 2005-12-19 2005-12-25
2005 53 2005-12-26 NULL 53 2005-12-26 2006-01-01
2006 1 NULL 2006-01-01 1 2005-12-26 2006-01-01
2006 2 2006-01-02 2006-01-08 2 2006-01-02 2006-01-08
You might try some dateadd logic...
dateadd(week, 23, '2011-01-01')
dateadd(day, 7, dateadd(week, 23, '2011-01-01'))
UPDATE:
select dateadd(day, 23, dateadd(week, 23, '2011-01-01')) , Datename(weekday,dateadd(day, 23, dateadd(week, 23, '2011-01-01')));
// RETURNS 7/4/2011, Monday
select Datename(weekday,dateadd(day, 23, dateadd(week, 23, '2011-01-01')));
// RETURNS Monday
EXAMPLE FROM: http://msdn.microsoft.com/en-us/library/ms186819.aspx
DECLARE #datetime2 datetime2 = '2007-01-01 13:10:10.1111111'
SELECT 'year', DATEADD(year,1,#datetime2)
UNION ALL
SELECT 'quarter',DATEADD(quarter,1,#datetime2)
UNION ALL
SELECT 'month',DATEADD(month,1,#datetime2)
UNION ALL
SELECT 'dayofyear',DATEADD(dayofyear,1,#datetime2)
UNION ALL
SELECT 'day',DATEADD(day,1,#datetime2)
UNION ALL
SELECT 'week',DATEADD(week,1,#datetime2)
UNION ALL
SELECT 'weekday',DATEADD(weekday,1,#datetime2)
UNION ALL
SELECT 'hour',DATEADD(hour,1,#datetime2)
UNION ALL
SELECT 'minute',DATEADD(minute,1,#datetime2)
UNION ALL
SELECT 'second',DATEADD(second,1,#datetime2)
UNION ALL
SELECT 'millisecond',DATEADD(millisecond,1,#datetime2)
UNION ALL
SELECT 'microsecond',DATEADD(microsecond,1,#datetime2)
UNION ALL
SELECT 'nanosecond',DATEADD(nanosecond,1,#datetime2);
/*
Year 2008-01-01 13:10:10.1111111
quarter 2007-04-01 13:10:10.1111111
month 2007-02-01 13:10:10.1111111
dayofyear 2007-01-02 13:10:10.1111111
day 2007-01-02 13:10:10.1111111
week 2007-01-08 13:10:10.1111111
weekday 2007-01-02 13:10:10.1111111
hour 2007-01-01 14:10:10.1111111
minute 2007-01-01 13:11:10.1111111
second 2007-01-01 13:10:11.1111111
millisecond 2007-01-01 13:10:10.1121111
microsecond 2007-01-01 13:10:10.1111121
nanosecond 2007-01-01 13:10:10.1111111
*/