How to select every Monday date and every Friday date in the year - sql

basically I want to be able to select monday and friday for every week in the year.
So for example this week coming i want 9/29/2014 and 10/3/2014, but i want this for every week in the year.

Here's one way (you might need to check which day of the week is setup to be the first, here I have Sunday as the first day of the week)
You can use a table with many rows (more than 365) to CROSS JOIN to in order to get a run of dates (a tally table).
My sys columns has over 800 rows in, you could use any other table or even CROSS JOIN a table onto itself to multiply up the number of rows
Here I used the row_number function to get a running count of rows and incremented the date by 1 day for each row:
select
dateadd(d, row_number() over (order by name), cast('31 Dec 2013' as datetime)) as dt
from sys.columns a
With the result set of dates now, it's trivial to check the day of week using datepart()
SELECT
dt,
datename(dw, dt)
FROM
(
select
dateadd(d, row_number() over (order by name), cast('31 Dec 2013' as datetime)) as dt
from
sys.columns a
) as dates
WHERE
(datepart(dw, dates.dt) = 2 OR datepart(dw, dates.dt) = 6)
AND dt >= '01 Jan 2014' AND dt < '01 Jan 2015'
Edit:
Here's an example SqlFiddle
http://sqlfiddle.com/#!6/d41d8/21757
Edit 2:
If you want them on the same row, days of the week at least are constant, you know Friday is always 4 days after Monday so do the same but only look for Mondays, then just add 4 days to the Monday...
SELECT
dt as MonDate,
datename(dw, dt) as MonDateName,
dateadd(d, 4, dt) as FriDate,
datename(dw, dateadd(d, 4, dt)) as FriDateName
FROM
(
select
dateadd(d, row_number() over (order by name), cast('31 Dec 2013' as datetime)) as dt
from
sys.columns a
) as dates
WHERE
datepart(dw, dates.dt) = 2
AND dt >= '01 Jan 2014' AND dt < '01 Jan 2015'
AND dt >= '01 Jan 2014' AND dt < '01 Jan 2015'
Example SqlFiddle for this:
http://sqlfiddle.com/#!6/d41d8/21764
(note that only a few rows come back because sys.columns is quite small on the SqlFiddle server, try another system table if this is a problem)

You can use a suitable table with numbers, like the master..spt_values table as basis for the range generation:
;WITH dates AS (
SELECT DATEADD(DAY,number,CAST('2014-01-01' AS DATE)) d
FROM master..spt_values WHERE TYPE = 'p'
AND number < 366
)
SELECT
Week = DATEPART(WEEK, d),
DayOfWeek = DATENAME(dw, d),
Date = d
FROM dates
WHERE DATENAME(dw, d) IN ('Monday', 'Friday')
-- or use datepart instead as datename might be specific to language
-- WHERE DATEPART(dw, d) IN (2,6)
Sample output:
Week DayOfWeek Date
----------- ------------------------------ ----------
1 Friday 2014-01-03
2 Monday 2014-01-06
2 Friday 2014-01-10
3 Monday 2014-01-13
3 Friday 2014-01-17
4 Monday 2014-01-20
4 Friday 2014-01-24
5 Monday 2014-01-27
5 Friday 2014-01-31

SELECT extract(isodow from "date_source") as datee 1-monday 7-sunday
and then in WHERE write datee IN ('1','2'....)

Related

I need data from Prior Monday to saturday when i run my interface on Tuesday at 1:30am. utlized a example query

select *
from VP_TIMESHTPUNCHV42
where (EVENTDATE>=getdate()-8) AND (EVENTDATE <=getdate()-3)
AND PERSONNUM = '668795'
so it should -9 or -8 here? please help me understand about the dates and what dates will be included here ?
If my Tuesday is 15th Oct and the previous Sat is 12thoct and mon is 7thoct
I need data from Mon7th oct to sat12th oct
if you want to get data from Monday to Saturday. WeekDay is from 2(Monday) to 7(Saturday)
select *
from VP_TIMESHTPUNCHV42
where datepart(weekday, EVENTDATE) between 2 and 7 AND PERSONNUM = '668795'
or (if only within this week)
select *
from VP_TIMESHTPUNCHV42
where EVENTDATE between getdate() - 1 and getdate() + 5 AND PERSONNUM = '668795'
select *
from VP_TIMESHTPUNCHV42
where EVENTDATE between dateadd(day, -1, cast(getdate() as date)) and dateadd(day, 5, cast(getdate() as date))
and PERSONNUM = '668795'

SQL: First day of week Monday

I would like to display Monday as the first day of the week and Sunday the last day of the week.
I am using for this report the Report server.
my query:
Select
Datum,
Sum(Prod) as Prod
FROM (
Select
intervaldate as Datum,
Sum(case when TabName = 'Produzierte Dosen' then DisplayUnits else 0 end) as Prod
from vwOeeIntervalCount
where
IntervalDateWeek >= dateadd(wk, datediff(wk, 0, getdate()) - 1, 0)
and IntervalDateWeek < dateadd(wk, datediff(wk, 0, getdate()), 0)
and IntervalDate >= dateadd(day,datediff(day,0,GETDATE())-6,0)
AND IntervalDate < dateadd(day,datediff(day,0,GETDATE()),0)
and CalculationName = 'Packaging'
group by intervaldate
)c
group by Datum
Here the result:
Date |Prod
2018-02-25 00:00:00.000 |1836528
2018-02-26 00:00:00.000 |8131127,99999999
EDIT:
Sorry here is my question.
I would like to display the Monday as the first day of the week. My query displays the Sunday as the first day of the week.
How can I do that?
By default MS SQL Server has configured sunday as first day of a week.
You can set the server config for the first day of a week to any day with the following command:
SET DATEFIRST { number | #number_var }
Value First day of the week is
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
7 (default, U.S. English) Sunday
Source: https://learn.microsoft.com/en-us/sql/t-sql/statements/set-datefirst-transact-sql
you can use this to the current week:
/*-- Week Start
--1->Sunday --2->Monday....*/
SELECT CAST(DATEADD(dd, -(DATEPART(dw, GETDATE()))+2, GETDATE()) AS DATE) [WeekStart],
CAST(DATEADD(dd, 8-(DATEPART(dw, GETDATE())), GETDATE()) AS DATE) [WeekEnd]
/*-- Week End
--7->Saturday --8-> Sunday...*/
Running this today will produce this result:
WeekStart WeekEnd
---------- ----------
2018-02-26 2018-03-04
if you have dates in your table, you can use them instead of the GETDATE()

Auto pickup dates from SQL Server - T-SQL

I am looking for some T-SQL code that should pick the date which is "One Year back from current date (at the same time last Sunday in the month of January)".
For example:
Current day expected result
2017-02-05 2016-01-31
2017-01-05 2015-01-25
2018-02-19 2017-01-29
2018-01-19 2016-01-31
2019-02-28 2018-01-28
Please note: The year starts from last Sunday in January
I have some T-SQL code which is being used in SQL Server 2014:
select
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(GetDate()) = 1 THEN CONVERT(VARCHAR(4), GetDate(), 112) - 1 ELSE CONVERT(VARCHAR(4), GetDate(), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)
The above code picks the date for current year's (last Sunday in January month). But I want T-SQL code to pick last year's (last Sunday's date in January month) date.
In detail - I want T-SQL code to produce expected result from below table
Current day T-SQL code answer expected result
2017-02-05 2017-01-29 2016-01-31
2017-01-05 2016-01-31 2015-01-25
2018-02-19 2018-01-28 2017-01-29
2018-01-19 2017-01-29 2016-01-31
2019-02-28 2019-01-27 2018-01-28
Any help please.
The best thing for this question is a numbers and date table. This answer shows you how to create one. Such a table is very handsome in many situations...
If I understand this correctly, you want the last Sunday in January of the previous year in all cases? Try this:
DECLARE #dummy TABLE(ID INT IDENTITY,YourDate DATE);
INSERT INTO #dummy VALUES
('2017-02-05'),('2017-01-05'),('2018-02-19'),('2018-01-19'),('2019-02-28');
WITH Years AS
(
SELECT * FROM (VALUES(2010),(2011),(2012),(2013),(2014),(2015),(2016),(2017),(2018),(2019),(2020)) AS t(Yr)
)
,LastSundays AS
(
SELECT Yr AS TheYear
,DATEADD(DAY,(DATEPART(WEEKDAY,LastOfJanuary) % 7)*(-1),LastOfJanuary) AS LastSundayOfJanuary
FROM Years
CROSS APPLY(SELECT CAST(CAST(Yr AS VARCHAR(4)) + '0131' AS DATE)) AS t(LastOfJanuary)
)
SELECT *
FROM #dummy AS d
INNER JOIN LastSundays AS ls ON YEAR(DATEADD(YEAR,-1,d.YourDate))=ls.TheYear;
The result (I do not understand row 2 and 4 completely...)
ID YourDate TheYear LastSundayOfJanuary
1 2017-02-05 2016 2016-01-31
2 2017-01-05 2016 2016-01-31 <--Your sample data is different...
3 2018-02-19 2017 2017-01-29
4 2018-01-19 2017 2017-01-29 <--Your sample data is different...
5 2019-02-28 2018 2018-01-28
Hint You might need to introduce ##DATEFIRST into your calculations...
Here is a way to do it without a date table (which is still a good idea BTW). Tested on all your inputs and it delivers the correct output each time. Obviously you would refactor this a bit as it's longwinded, just to show each step.
/* The input date. */
DECLARE
#input DATE = '2019-02-28';
/* The input date less one year. */
DECLARE
#date_minus_one_year DATE = DATEADD(yy,-1,#input);
/* The year part of the input date less one year. */
DECLARE
#year_date_part INT = DATEPART(yy,#date_minus_one_year);
/* 31 Jan of the previous year. */
DECLARE
#prev_year_jan_eom DATE = CAST(CAST(#year_date_part AS VARCHAR(4))+'-01-31' AS DATE);
/* What day of the week is 31 Jan of the previous year? */
DECLARE
#previous_eom_dw_part INT = DATEPART(dw,#prev_year_jan_eom);
/* Offest 31 Jan to the previous Sunday, won't change if the 31st is itself a Sunday. */
DECLARE
#output DATE = DATEADD(dd,1 - #previous_eom_dw_part,#prev_year_jan_eom);
/* Input and output */
SELECT
#input input
,#output [output];
I didn't think of a way to do it without the conditional in a case. It also uses the trick of casting a numeric year value to a January 1st date.
select case
when
datepart(dayofyear, dt) >
31 - datepart(weekday, dateadd(day, 30, cast(year(dt) as varchar(4))))
then
dateadd(day,
31 - datepart(weekday, dateadd(day, 30, cast(year(dt) as varchar(4)))),
cast(year(dt) as varchar(4))
)
else
dateadd(day,
31 - datepart(weekday, dateadd(day, 30, cast(year(dt) - 1 as varchar(4)))),
cast(year(dt) - 1 as varchar(4))
)
end
from (values
('20100201'), ('20110301'), ('20120401'),
('20130501'), ('20140601'), ('20150701'),
('20160801'), ('20170901'), ('20181001')
) t(dt)
Just for fun (untested)
select
dateadd(week,
-52 * ceil(sign(datediff(day, dt, hs)) + 0.5),
js
)
from
(select <date> dt) as t
cross apply
(
select 31 - datepart(weekday,
datefromparts(year(dt), 1, 31) as js
) t2;
SELECT
convert(varchar(10), DATEADD(day, DATEDIFF(day, '19000107', DATEADD(month, DATEDIFF(MONTH, 0, CONVERT(date, CONVERT(VARCHAR(4), (CASE WHEN MONTH(DATEADD(year,-1,GetDate())) = 1 THEN CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) - 1 ELSE CONVERT(VARCHAR(4), DATEADD(year,-1,GetDate()), 112) END), 112) + '0101')), 30)) / 7 * 7, '19000107'), 120)

How to get month value using week value sql server

I want to get month value using week no.
I have week numbers stored in a table with year value.
How to query database to get month value using that week value.
I am using SQL
You can try this:
SELECT DATEPART(m,DATEADD(wk, DATEDIFF(wk, 6, '1/1/' + CAST(t.year as VARCHAR(4))) + (t.week-1), 6))
It depends on how you're classing your week numbers, For example, if we assume that week numbers start on a Monday then we'd have to say that week 1 in 2016 actually started on Monday 28th of December 2015 and finished on Sunday 3rd January 2016. If this is how your week numbers are set up then you can use the method below
Sample Data;
CREATE TABLE #DateTable (WeekNum int, YearNum int)
INSERT INTO #DateTable (WeekNum, YearNum)
VALUES
(1,2016)
,(2,2016)
,(3,2016)
,(4,2016)
,(5,2016)
,(6,2016)
,(7,2016)
We will then cast the week and year into a date, then convert this to a month;
SELECT
WeekNum
,YearNum
,DATEADD(wk, DATEDIFF(wk, 7, '1/1/' + CONVERT(varchar(4),YearNum)) + (WeekNum-1), 7) AS WeekStart
,DATEPART(mm,DATEADD(wk, DATEDIFF(wk, 7, '1/1/' + CONVERT(varchar(4),YearNum)) + (WeekNum-1), 7)) MonthNum
(Edit: updated as source is int)
Gives these results;
WeekNum YearNum WeekStart MonthNum
1 2016 2015-12-28 00:00:00.000 12
2 2016 2016-01-04 00:00:00.000 1
3 2016 2016-01-11 00:00:00.000 1
4 2016 2016-01-18 00:00:00.000 1
5 2016 2016-01-25 00:00:00.000 1
6 2016 2016-02-01 00:00:00.000 2
7 2016 2016-02-08 00:00:00.000 2
You can't go from week number to month because weeks can occur in two different months. For example the 31st Jan 2016 and 1st Feb 2016 are both in week 6.
SELECT DATEPART(WEEK, '2016-01-31')
SELECT DATEPART(WEEK, '2016-02-01')
You can try the query below:
SELECT
[Week],
[Year],
'Output-Month' = MONTH(DATEADD(WEEK, [Week], DATEADD(WEEK, DATEDIFF(WEEK, '19050101', '01/01/' + CAST([Year] AS VARCHAR(4))), '19050101')))
FROM YourTable
1st is to get the 1st day of the year using this:
DATEADD(WEEK, DATEDIFF(WEEK, '19050101', '01/01/' + CAST([Year] AS VARCHAR(4))), '19050101')
2nd is to add your number of week using this:
DATEADD(WEEK, [Week], 'From 1st result')
Last is getting the number of Month using the MONTH function.

MSSQL - Getting last 6 weeks returns last 8 weeks

I am having a problem with week numbers. The customers week starts on a Tuesday, so ends on a Monday. So I have done:
Set DateFirst 2
When I then use
DateAdd(ww,#WeeksToShow, Date)
It occasionally gives me 8 weeks of information. I think it is because it goes over to the previous year, but I am not sure how to fix it.
If I do:
(DatePart(dy,Date) / 7) - #WeeksToShow
Then it works better, but obviously doesn't work going through to previous years as it just goes to minus figures.
Edit:
My currently SQL (If it helps at all without any data)
Set DateFirst 2
Select
DATEPART(yyyy,SessionDate) as YearNo,
DATEPART(ww,SessionDate) as WeekNo,
DATEADD(DAY, 1 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate +SessionTime AS DATE)) [WeekStart],
DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE)) [WeekEnd],
DateName(dw,DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE))) as WeekEndName,
Case when #ConsolidateSites = 1 then 0 else SiteNo end as SiteNo,
Case when #ConsolidateSites = 1 then 'All' else CfgSites.Name end as SiteName,
GroupNo,
GroupName,
DeptNo,
DeptName,
SDeptNo,
SDeptName,
PluNo,
PluDescription,
SUM(Qty) as SalesQty,
SUM(Value) as SalesValue
From
PluSalesExtended
Left Join
CfgSites on PluSalesExtended.SiteNo = CfgSites.No
Where
Exists (Select Descendant from DescendantSites where Parent in (#SiteNo) and Descendant = PluSalesExtended.SiteNo)
AND (DATEPART(WW,SessionDate + SessionTime) !=DATEPART(WW,GETDATE()))
AND SessionDate + SessionTime between DATEADD(ww,#NumberOfWeeks * -1,#StartingDate) and #StartingDate
AND TermNo = 0
AND PluEntryType <> 4
Group by
DATEPART(yyyy,SessionDate),
DATEPART(ww,SessionDate),
DATEADD(DAY, 1 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate +SessionTime AS DATE)),
DATEADD(DAY, 7 - DATEPART(WEEKDAY, SessionDate + SessionTime), CAST(SessionDate + SessionTime AS DATE)),
Case when #ConsolidateSites = 1 then 0 else SiteNo end,
Case when #ConsolidateSites = 1 then 'All' else CfgSites.Name end,
GroupNo,
GroupName,
DeptNo,
DeptName,
SDeptNo,
SDeptName,
PluNo,
PluDescription
order by WeekEnd
There are two issues here, the first is that I suspect you are defining 8 weeks of data as having 8 different values for DATEPART(WEEK, in which case you can replicate the root cause of the issue by looking at what ISO would define as the first week of 2015:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(WEEK, Date)
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which gives:
Date Week
-----------------
2014-12-29 52
2014-12-30 53
2014-12-31 53
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
So although you only have 7 days, you have 3 different week numbers. The problem is that DATEPART(WEEK is quite a simplistic function, and will simply return the number of week boundaries passed since the first day of the year, a better function would be ISO_WEEK since this takes into account year boundaries nicely:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(ISO_WEEK, Date)
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which gives:
Date Week
-----------------
2014-12-29 1
2014-12-30 1
2014-12-31 1
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
The problem is, that this does not take into account that the week starts on Tuesday, since the ISO week runs Monday to Sunday, you could adapt your usage slightly to get the week number of the day before:
SET DATEFIRST 2;
SELECT Date, Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date))
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Which would give:
Date Week
-----------------
2014-12-29 52
2014-12-30 1
2014-12-31 1
2015-01-01 1
2015-01-02 1
2015-01-03 1
2015-01-04 1
So Monday the 29th December is now recognized as the previous week. The problem is that there is no ISO_YEAR built in function, so you will need to define your own. This is a fairly trivial function, even so I almost never create scalar functions because they perform terribly, instead I use an inline table valued function, so for this I would use:
CREATE FUNCTION dbo.ISOYear (#Date DATETIME)
RETURNS TABLE
AS
RETURN
( SELECT IsoYear = DATEPART(YEAR, #Date) +
CASE
-- Special cases: Jan 1-3 may belong to the previous year
WHEN (DATEPART(MONTH, #Date) = 1 AND DATEPART(ISO_WEEK, #Date) > 50) THEN -1
-- Special case: Dec 29-31 may belong to the next year
WHEN (DATEPART(MONTH, #Date) = 12 AND DATEPART(ISO_WEEK, #Date) < 45) THEN 1
ELSE 0
END
);
Which just requires a subquery to be used, but the extra typing is worth it in terms of performance:
SET DATEFIRST 2;
SELECT Date,
Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date)),
Year = (SELECT ISOYear FROM dbo.ISOYear(DATEADD(DAY, -1, Date)))
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date);
Or you can use CROSS APPLY:
SET DATEFIRST 2;
SELECT Date,
Week = DATEPART(ISO_WEEK, DATEADD(DAY, -1, Date)),
Year = y.ISOYear
FROM (VALUES
('20141229'), ('20141230'), ('20141231'), ('20150101'),
('20150102'), ('20150103'), ('20150104')
) d (Date)
CROSS APPLY dbo.ISOYear(d.Date) y;
Which gives:
Date Week Year
---------------------------
2014-12-29 52 2014
2014-12-30 1 2015
2014-12-31 1 2015
2015-01-01 1 2015
2015-01-02 1 2015
2015-01-03 1 2015
2015-01-04 1 2015
Even with this method, by simply getting a date 6 weeks ago you sill still end up with 7 weeks if the date you are using is not a Tuesday, because you will have 5 full weeks, and a part week at the start and a part week at the end, this is the second issue. So you need to make sure your start date is a Tuesday. The following will get you Tuesday of 7 weeks ago:
SELECT CAST(DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), DATEADD(WEEK, -6, GETDATE())) AS DATE);
The logic of this is explained better in this answer, the following is the part that will get the start of the week (based on your datefirst settings):
SELECT DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), GETDATE());
Then all I have done is substitute the second GETDATE() with DATEADD(WEEK, -6, GETDATE()) so that it is getting the start of the week 6 weeks ago, then there is just a cast to date to remove the time element from it.
This will get you current week + 5 previous weeks starting tuesday:
WHERE dateadd(week, datediff(d, 0, getdate()-1)/7 - 4, 1) <= yourdatecolumn
This will show examples:
DECLARE #wks int = 6 -- Weeks To Show
SELECT
dateadd(week, datediff(d, 0, getdate()-1)/7 - 4, 1) tuesday5weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - 5, 1) tuesday6weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - 6, 1) tuesday7weeksago,
dateadd(week, datediff(d, 0, getdate()-1)/7 - #wks + 1, 1) tuesdaydynamicweeksago
Result:
tuesday5weeksago tuesday6weeksago tuesday7weeksago tuesdaydynamicweeksago
2015-01-27 2015-01-20 2015-01-13 2015-01-20