How to insert weekdays names in sql column based on given date? - sql

I wanted to know how to insert weekday names in a column in sql server based on the current date. I want to insert the days until current day. For example, I want something as per the following column for today (2014-12-04),
day_of_week
-----------
Monday
Tuesday
Wednesday
Thursday
On next Tuesday(2014-12-09), I want to display,
day_of_week
-----------
Monday
Tuesday
Let me know how can I do this in sql server 2012?
Any help will be appreciated.
Thanks.

Something like this should work.
select datename(weekday,n)
from (VALUES (0),(1),(2),(3),(4),(5),(6)) wdays(n)
where n < datepart(weekday,'20141209') - 1
And if you're not using sql 2008 and up you can do
select datename(weekday,n)
from (select 0
union all
select 1
union all
select 2
union all
select 3
union all
select 4
union all
select 5
union all
select 6
) wdays(n)
where n < datepart(weekday,'20141209') - 1

It can also be done using a recursive CTE:
;WITH cte AS
(
SELECT DATENAME(weekday,getdate()) AS NameOfDay,
DAY(getdate()) AS NumberOfDay,
getdate() AS curDate
UNION ALL
SELECT DATENAME(weekday,DATEADD(day, -1, curDate)) As NameOfDay,
DAY(DATEADD(day, -1, curDate)) AS NumberOfDay,
DATEADD(day, -1, curDate) AS curDate
FROM cte
WHERE DAY(GETDATE()) - DAY(DATEADD(day, -1, curDate)) >= 0
)
SELECT NameOfDay
FROM cte
ORDER BY NumberOfDay

Related

How to loop through each value from CTE

I am working only on queries for now and not TSQL. So i want to fetch my results thru query.
I want to display first monday of every month. I have comeup with a query to find the dates of every month in tht year thru CTE. (So my CTE gives 12 dates).
Now , i want to check each date and get the nearest monday. That would be my first monday of that month.
I am unable to go thru each date in my query.
How can i work on this result set?
Thanks
with
Wk_num
as
(select 1 as n
union all
select n=n+1
from wk_num
where n <12)
select dateadd(month,n,getdate()) from wk_num
A relatively simple method use modulo arithmetic:
with cte as (
select convert(date, '2019-01-01') as dte
union all
select dateadd(month, 1, dte)
from cte
where dateadd(month, 1, dte) < '2020-01-01'
)
select dte,
dateadd(day, (9 - datepart(weekday, dte)) % 7, dte) as first_monday
from cte;
This assumes that the weekday numbers starts with 1 on Sunday.
Here is the code to actually get the first day of each month and the first Monday of each month (This doesn't use any complex functions just simple date functions):
with Wk_num as
(select 1 as n
union all
select n=n+1 from wk_num where n <12)
select dateadd(month,n,datefromparts(year(getdate()),month(getdate()),1)) as FirstDay,
dateadd(day,iif(9-datepart(dw,dateadd(month,n,datefromparts(year(getdate()),month(getdate()),1)))>7,2-datepart(dw,dateadd(month,n,datefromparts(year(getdate()),month(getdate()),1))),9-datepart(dw,dateadd(month,n,datefromparts(year(getdate()),month(getdate()),1)))),dateadd(month,n,datefromparts(year(getdate()),month(getdate()),1))) as FirstMonday
from wk_num

get 5th previous date from current date through SQL except public holiday

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...

How can I select the 1st of every month for the last 5 years in sql?

I am trying to get a list of the 1st of the Month for the last 5 years. How can i do that ?? I have a select statement:
select convert(varchar(10), dateadd(mm,Datediff(mm,0,getdate()),0),111) as StartDate
but i am not sure how to get a list for every month.
with dates
as (
select dateadd(month, datediff(month, 0, getdate()), 0) as date
union all
select dateadd(month, - 1, date)
from dates
)
select top 60 *
from dates
with cte as (
select DATEFROMPARTS ( datepart(yyyy,getdate()), datepart(mm,getdate()), 1 ) as startdate
union all
select dateadd(month,-1,startdate) from dates
where datediff(year,startdate,getdate()) <> 5 )
select CONVERT ( varchar(12), startdate , 107 ) from cte;

How to make temporary table with row for each of last 24 hours?

Basically, I want query that would generate result with a row for each hour in last 24 hours:
01/01/2011 00:00:00
01/01/2011 01:00:00
01/01/2011 02:00:00
...
Any way I can do that without cursors and temp tables?
One row for each hour for a given date (SQL Server solution).
select dateadd(hour, Number, '20110101')
from master..spt_values
where type = 'P' and
number between 0 and 23
result with a row for each hour in last 24 hours
select dateadd(hour, datediff(hour, 0, getdate()) - number, 0)
from master..spt_values
where type = 'P' and
number between 0 and 23
Well... on SQL Server you could do this...
WITH cte
AS
(
SELECT CAST('1-jan-2011' AS DATETIME) AS 'date'
UNION ALL
SELECT DATEADD(hh, 1, [date]) FROM cte WHERE [date] < '1-jan-2011 23:00'
)
SELECT [date] FROM cte
...but in reality, a table with just the hours (0 to 23) would be more useful, because you could then add the hour to any date.
WITH cte
AS
(
SELECT 0 as 'Hour'
UNION ALL
SELECT hour + 1 FROM cte WHERE hour < 23
)
SELECT DateAdd(hh, hour, '1-jan-2010') FROM cte
Another, slightly more isoteric way would be to use the row_number ranking function against the first 24 rows of some abitrary object (like spt_values)...
WITH cte AS
(
SELECT n
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY type ) FROM master..spt_values ) D ( n )
WHERE n < 24
)
SELECT dateadd(hh,n,'01-jan-2011') FROM cte
Here is the simple way...
SELECT '01/01/2011 00:00:00' as [hour], blah, blah2
UNION ALL
SELECT '01/01/2011 01:00:00' as [hour], blah, blah2
UNION ALL
SELECT '01/01/2011 02:00:00' as [hour], blah, blah2
UNION ALL
...etc 24 times.
On a particular platform or solving a particular problem there might be a better way, but you will have to give more detail to get that answer.

Select last 30 days with a sql query

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