I need to find the last day of a month in the american (mm-dd-yyyy) format for a column which has yymm(nvarchar format).
example:- for 1601---> 01-31-2016
Thank you for help!
Using convert to get the date of the 1st of the month, then dateadd to get the next month, and one more dateadd to get one day before:
DECLARE #D char(4) = '1601'
SELECT DATEADD(DAY, -1, DATEADD(MONTH, 1, CONVERT(date, #D + '01', 12)))
Result:
2016-01-31
With a string of 1601, we just need to append a 01 because the century will be assumed. This new string of 160101 can be converted into a date.
Example
select convert(varchar(10),dateadd(day,-1,dateadd(month,1,YourCol+'01')),101)
From YourTable
Returns
01/31/2016
Since you said year 20XX...
declare #oddDate nvarchar(4) = '1601'
select
DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, '20' + cast(YY as varchar(2)) + cast(MM as varchar(2)) + '01') + 1, 0)) as LastDayof20Year
,'20' + cast(YY as varchar(2)) + cast(MM as varchar(2)) + '01' as MadeUpDate
from
(select
left(#oddDate,2) as YY
,right(#oddDate,2) as MM) x
Or simply...
select
DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, '20' + cast(left(#oddDate,2) as varchar(2)) + cast(right(#oddDate,2) as varchar(2)) + '01') + 1, 0)) as LastDayof20Year
Something like the following should do the trick...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
CREATE TABLE #TestData (
CharDate CHAR(4) NOT NULL
);
INSERT #TestData (CharDate) VALUES
('9801'), ('9902'), ('0012'), ('0202'), ('1005'), ('1503');
--============================================================
SELECT
FormattedEOM = CONVERT(CHAR(10), em.EndOfMonth, 101)
FROM
#TestData td
CROSS APPLY ( VALUES (CASE WHEN CAST(LEFT(td.CharDate, 2) AS INT) > 30 THEN '19' ELSE '20' END) ) c (Century)
CROSS APPLY ( VALUES (DATEFROMPARTS(CONCAT(c.Century, LEFT(td.CharDate, 2)), RIGHT(td.CharDate, 2), 1)) ) fm (FirstOfMonth)
CROSS APPLY ( VALUES (EOMONTH(fm.FirstOfMonth)) ) em (EndOfMonth);
HTH,
Jason
Edit: The following should work with 2008....
SELECT
FormattedEOM = CONVERT(CHAR(10), em.EndOfMonth, 101)
FROM
#TestData td
CROSS APPLY ( VALUES (CASE WHEN CAST(LEFT(td.CharDate, 2) AS INT) > 30 THEN '19' ELSE '20' END) ) c (Century)
CROSS APPLY ( VALUES (CAST(c.Century + td.CharDate + '01' AS DATE)) ) fm (FirstOfMonth)
CROSS APPLY ( VALUES (DATEADD(mm, 1, fm.FirstOfMonth)) ) nm (NextMonth)
CROSS APPLY ( VALUES (DATEADD(dd, -1, nm.NextMonth)) ) em (EndOfMonth);
Related
I need to check if a given day is the last sunday of any year, if yes the return 1 using TSQL only.
I do not have much idea about TSQL.
SQL Server has a problem with weekdays, because they can be affected by internationalization settings. Assuming the defaults, you can do:
select dateadd(day,
1 - datepart(weekday, datefromparts(#year, 12, 31)),
datefromparts(#year, 12, 31)
)
Otherwise, you'll need to do a case expression to turn the day of the week into a number.
In an older version of SQL Server, you could do:
select dateadd(day,
1 - datepart(weekday, cast(#year + '0101' as date)),
cast(#year + '0101' as date)
)
I haven't worked with tsql specifically but if my sql knowledge and googling is good enough then something like this should do the trick:
... WHERE DATEPART(dw, date) = 7 and DATEDIFF (d, date, DATEFROMPARTS (DATEPART(yyyy, date), 12, 31)) <= 6
Basically we check if that day is Sunday at first and then if it's less than week away from last day of the year
Using Mr. Gordon's query, following IIF() returns 1 if given day is last Sunday of the year, returns 0 if it is not.
Using 2018 as year and 2018-12-30 as given date. You can replace values with variables.
select IIF( DATEDIFF(DAY,'2018-12-30',
DATEADD(day,
1 - datepart(weekday, datefromparts(2018, 12, 31)),
datefromparts(2018, 12, 31)
)) = 0, 1, 0)
You can use this function
Function Code :
create FUNCTION CheckIsSaturday
(
#date DATETIME
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE #result INT
DECLARE #DayOfWeek NVARCHAR(22)
DECLARE #LastDayOfYear DATETIME
select #LastDayOfYear=DATEADD(yy, DATEDIFF(yy, 0, #date) + 1, -1)
SELECT #DayOfWeek=DATENAME(dw, #date)
IF(#DayOfWeek='Saturday' AND DATEDIFF(dd,#date,#LastDayOfYear)<7)
RETURN 1;
RETURN 0;
END
GO
function Usage:
SELECT dbo.CheckIsSaturday('2017-12-23')
This becomes quite trivial if you have a Calendar Table
DECLARE #CheckDate DATE = '20181230'
;WITH cteGetDates AS
(
SELECT
[Date], WeekDayName, WeekOfMonth, [MonthName], [Year]
,LastDOWInMonth = ROW_NUMBER() OVER
(
PARTITION BY FirstDayOfMonth, [Weekday]
ORDER BY [Date] DESC
)
FROM
dbo.DateDimension
)
SELECT * FROM cteGetDates D
WHERE D.LastDOWInMonth = 1 AND D.WeekDayName = 'Sunday' and D.MonthName = 'December' AND D.[Date] = #CheckDate
You can also use this one to get every last day of the year:
;WITH getlastdaysofyear ( LastDay, DayCnt ) AS (
SELECT DATEADD(dd, -DAY(DATEADD(mm, 1, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) + 1, -1))),
DATEADD(mm, 1, DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) + 1, -1))),
0 AS DayCnt
UNION ALL
SELECT LastDay,
DayCnt + 1
FROM getlastdaysofyear
)
SELECT *
FROM ( SELECT TOP 7 DATEADD(DD, -DayCnt, LastDay) LastDate,
'Last ' + DATENAME(Weekday,DATEADD(DD, -DayCnt, LastDay)) AS DayStatus
FROM getlastdaysofyear ) T
ORDER BY DATEPART(Weekday, LastDate)
Hope you like it :)
I have a client who reports on 13 27 day periods in the financial year and I am trying to work out some dynamic SQL to identify what reporting period an invoice was raised in.
This is what I have so far but the while loop is crashing after the first loop.
IF OBJECT_ID('#Periods', 'U') IS NOT NULL
drop table #Periods
create table #Periods
([start_date] date, [end_date] date, Period varchar(3) )
declare #LYdt datetime,
#CYdt datetime,
#Period int
SET #Period = 0
SET #LYdt = '09/01/2016'
SET #CYdt = '09/01/2017'
While #Period <=13
insert #Periods
select
[Start_Date] = dateadd(mm,datediff(mm,'',#LYdt),'') - datepart(dw,dateadd(mm,datediff(mm,'',#LYdt),'')+0)+ 22,
[End Date] = (dateadd(mm,datediff(mm,'',#LYdt),'') - datepart(dw,dateadd(mm,datediff(mm,'',#LYdt),'')+0)+ 22)+27,
[Period] = 'P'+ convert(varchar(2),#Period)
SET #Period = #Period + 1
SET #LYdt = dateadd(d,27,#LYdt)
SET #CYdt = dateadd(d,27,#CYdt)
Can anyone assist with where I have gone wrong please?
Dave
addiditonal:
sample result set of sql will look like this:
If you are trying to generate periods between two dates, you can use a recursive CTE:
with periods as (
select cast('2016-09-01' as date) as start_date, 1 as lev
union all
select dateadd(day, 27, start_date), lev + 1
from periods
where start_date < '2017-09-01'
)
select start_date,
lead(start_date) over (order by start_date) as end_date,
'P' + right('00' + cast(lev as varchar(255)), 2) as period_num
from periods;
EDIT:
You can do this just as easily by doing:
with periods as (
select cast('2016-09-01' as date) as start_date, 1 as lev
union all
select dateadd(day, 27, start_date), lev + 1
from periods
where start_date < '2017-09-01'
)
select start_date,
dateadd(day, 27, start_date) as end_date,
'P' + right('00' + cast(lev as varchar(255)), 2) as period_num
from periods;
despite agreeing with you guys that they need to provide the dates for me to work with, I couldn't let the task beat me so I have finally written up an answer that works.
It combines a scalar function for concatenating dates that I found here (Thanks to Brian for the function):
Create a date with T-SQL
With Gordons Code from above
to get the final product:
declare #LY datetime,
#TY datetime,
#FD datetime,
#TY_DATE datetime,
#LY_DATE datetime,
#FD_DATE datetime,
#Use_date datetime
select #LY = dbo.datemaker(datepart(year,getdate())-2, 9, 1)
select #TY = dbo.datemaker(datepart(year,getdate())-1, 9, 1)
Select #FD = dbo.datemaker(datepart(year,getdate()), 9, 1)
select #LY_DATE = dateadd(mm,datediff(mm,'',#LY),'') - datepart(dw,dateadd(mm,datediff(mm,'',#LY),'')+0)+ 22
select #TY_DATE = dateadd(mm,datediff(mm,'',#TY),'') - datepart(dw,dateadd(mm,datediff(mm,'',#TY),'')+0)+ 22
select #FD_DATE = dateadd(mm,datediff(mm,'',#FD),'') - datepart(dw,dateadd(mm,datediff(mm,'',#FD),'')+0)+ 22
select #use_date = case when(convert(date,getdate()) >= #FD_DATE) then #TY_DATE ELSE #LY_DATE END;
with periods as (
select #use_date as start_date, 1 as lev
union all
select dateadd(day, 28, start_date), lev + 1
from periods
where start_date < dateadd(year,1,start_date) and
lev <=12)
select start_date as [Start_Date],
dateadd(day, 27, start_date) as end_date,
'P' + right('00' + cast(lev as varchar(255)), 2) +'LY' as period_num
from periods
union all
select dateadd(year,1,start_date) as [Start_Date],
dateadd(year,1,dateadd(day, 27, start_date)) as end_date,
'P' + right('00' + cast(lev as varchar(255)), 2) +'TY' as period_num
from periods;
CREATE FUNCTION [dbo].[Datemaker]
(
#Year INT,
#Month INT,
#DayOfMonth INT
)
RETURNS DATETIME
AS
BEGIN
RETURN
DATEADD(day, #DayOfMonth - 1,
DATEADD(month, #Month - 1,
DATEADD(Year, #Year-1900, 0)))
END
GO
Thanks to all of you for contributing.
Regards,
Dave
My scenario is as below:
#StartDate = 13th of current month
#EndDate = 12th of next month.
I want to get all the date with the day-name for Mondays, Tuesdays, Wednesdays, Thursdays, Fridays, Saturdays and Sundays lying between the start and end date.
Try this:
declare #startDate datetime = '2016-01-13'
declare #endDate datetime = '2016-02-12'
;with dateRange as
(
select [Date] = dateadd(dd, 1, #startDate)
where dateadd(dd, 1, #startDate) < #endDate
union all
select dateadd(dd, 1, [Date])
from dateRange
where dateadd(dd, 1, [Date]) < #endDate
)
select [Date], datename(dw,[Date])
from dateRange
To count the number of each day as per your comment (this should be part of the question really), change the last part of James' answer to this:
select datename(dw,[Date]) as day_name, count([Date]) as number_days
from dateRange group by datename(dw,[Date]), datepart(DW,[Date])
order by datepart(DW,[Date]);
You can try something like this :
DECLARE #StartDate DATETIME
DECLARE #StartDateFixed DATETIME
DECLARE #EndDate DATETIME
DECLARE #NumberOfDays int
SET #StartDate = '2016/01/01'
SET #EndDate = '2016/01/02'
SET #NumberOfDays = DATEDIFF(DAY,#StartDate,#EndDate) + 1
SET #StartDateFixed = DATEADD(DD,-1,#StartDate)
SELECT WeekDay , COUNT(WeekDay)
FROM (
SELECT TOP (#NumberOfDays) WeekDay = DATENAME(DW , DATEADD(DAY,ROW_NUMBER() OVER(ORDER BY spt.name), #StartDateFixed))
FROM [master].[dbo].[spt_values] spt
) A
GROUP BY WeekDay
The output will be
WeekDay
------------------------------ -----------
Friday 1
Saturday 1
(2 row(s) affected)
In case if you need to get current and next date from date number specified such as 13 and 12
Current Month
DECLARE #cur_mont INT = (SELECT MONTH(GETDATE()))
Current Year
DECLARE #cur_year INT = (SELECT YEAR(GETDATE()))
Next Month
DECLARE #nxt_mont INT = (SELECT MONTH(DATEADD(month, 1, GETDATE())))
Next Month year (In case of December year change)
DECLARE #nxt_year INT = (SELECT YEAR(DATEADD(month, 1, GETDATE())))
Create start date
DECLARE #startDate DATETIME = (SELECT CAST(CAST(#cur_year AS varchar) + '-' + CAST(#cur_mont AS varchar) + '-' + CAST(13 AS varchar) AS DATETIME))
Create end date
DECLARE #endDate DATETIME = (SELECT CAST(CAST(#nxt_year AS varchar) + '-' + CAST(#nxt_mont AS varchar) + '-' + CAST(12 AS varchar) AS DATETIME))
Dates between start and end date
SELECT TOP (DATEDIFF(DAY, #startDate, #endDate) + 1)
DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #startDate) AS Date,
DATENAME(DW, DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #startDate)) AS Day
FROM sys.all_objects a CROSS JOIN sys.all_objects b;
DECLARE #dayStart int = 13, --The day of current month
#dayEnd int = 12, --The day of another month
#howManyMonth int = 1, --How many month to take
#dateStart date,
#dateEnd date
--Here we determine range of the dates
SELECT #dateStart = CONVERT (date,
CAST(DATEPART(Year,GETDATE()) as nvarchar(5))+ '-' +
CASE WHEN LEN(CAST(DATEPART(Month,GETDATE()) as nvarchar(5))) = 1
THEN '0'+CAST(DATEPART(Month,GETDATE()) as nvarchar(5))
ELSE CAST(DATEPART(Month,GETDATE()) as nvarchar(5)) END + '-' +
CAST (#dayStart as nvarchar(5))),
#dateEnd = CONVERT (date,
CAST(DATEPART(Year,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))+ '-' +
CASE WHEN LEN(CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))) = 1
THEN '0'+CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5))
ELSE CAST(DATEPART(Month,DATEADD(Month,#howManyMonth,GETDATE())) as nvarchar(5)) END + '-' +
CAST (#dayEnd as nvarchar(5)))
;WITH cte AS (
SELECT #dateStart as date_
UNION ALL
SELECT DATEADD(day,1,date_)
FROM cte
WHERE DATEADD(day,1,date_) <= #dateEnd
)
--Get results
SELECT DATENAME(WEEKDAY,date_) as [DayOfWeek],
COUNT(*) as [DaysCount]
FROM cte
GROUP BY DATEPART(WEEKDAY,date_),
DATENAME(WEEKDAY,date_)
ORDER BY DATEPART(WEEKDAY,date_)
OPTION (MAXRECURSION 0)
Output:
DayOfWeek DaysCount
----------- -----------
Sunday 4
Monday 4
Tuesday 4
Wednesday 5
Thursday 5
Friday 4
Saturday 4
(7 row(s) affected
Just want to select all dates between cureent date and first day of month . I want to use fill all dates in a temp table
declare #temp table
(
ddate datetime
)
I have tried with with cte and i don't want to use while loop becuase i want to avoid while in stored procedure .
For example as today is 11-oct-2012
so temp table should have 11 rows starting from 1-oct-2012 to 11-oct-2012
Try this
DECLARE #startDate DATE=CAST(MONTH(GETDATE()) AS VARCHAR) + '/' + '01/' + + CAST(YEAR(GETDATE()) AS VARCHAR) -- mm/dd/yyyy
DECLARE #endDate DATE=GETDATE() -- mm/dd/yyyy
SELECT [Date] = DATEADD(Day,Number,#startDate)
FROM master..spt_values
WHERE Type='P'
AND DATEADD(day,Number,#startDate) <= #endDate
OR
DECLARE #startDate DATETIME=CAST(MONTH(GETDATE()) AS VARCHAR) + '/' + '01/' + + CAST(YEAR(GETDATE()) AS VARCHAR) -- mm/dd/yyyy
DECLARE #endDate DATETIME= GETDATE() -- mm/dd/yyyy
;WITH Calender AS
(
SELECT #startDate AS CalanderDate
UNION ALL
SELECT CalanderDate + 1 FROM Calender
WHERE CalanderDate + 1 <= #endDate
)
SELECT [Date] = CONVERT(VARCHAR(10),CalanderDate,25)
FROM Calender
OPTION (MAXRECURSION 0)
declare #temp table (ddate datetime);
insert #temp
select DATEDIFF(d,0,GetDate()-Number)
from master..spt_values
where type='p' and number < DatePart(d,Getdate())
order by 1;
use current_date add days of every the generated series to the days, the series could from the first day of the month subtract current_day to 0, such today 02 Jun, the series could be (-1, 0).
Try the following code:
DECLARE #startDate DATETIME=CAST(MONTH(GETDATE()) AS VARCHAR) + '/' + '01/' + + CAST(YEAR(GETDATE()) AS VARCHAR) -- mm/dd/yyyy
DECLARE #endDate DATETIME= CAST(MONTH(GETDATE()) AS VARCHAR) + '/' + '31/' + + CAST(YEAR(GETDATE()) AS VARCHAR) -- mm/dd/yyyy
;WITH Calender AS
(
SELECT #startDate AS CalanderDate
UNION ALL
SELECT CalanderDate + 1 FROM Calender
WHERE CalanderDate + 1 <= #endDate
)
SELECT [Date] = CONVERT(VARCHAR(10),CalanderDate,25)
FROM Calender
OPTION (MAXRECURSION 0)
I want to code a query to calculate the total birthday moth based on month . Here is the sample data . Two person's bithday are April, 1980 .
How to write this query ?
John 02/21/1980
Peter 02/22/1980
Lucy 04/21/1980
------ result -----
01/1980 0
02/1980 2
03/1980 0
04/1980 1
05/1980 0
.....
You can loop for every months like this:
DECLARE #month INT
DECLARE #year INT
DECLARE #result TABLE (MonthYear varchar(7),BirthdaysCount INT)
SET #month = 1
SET #year = 1980
WHILE(#month < 13)
BEGIN
INSERT INTO #result
SELECT (CAST(#month as VARCHAR) + '/' + CAST(#year as VARCHAR)),
COUNT(*)
FROM test
WHERE MONTH(birth) = #month AND YEAR(birth) = #year
SET #month = #month + 1
END
select * from #result
See the fiddle: http://sqlfiddle.com/#!3/20692/2
In MySQL you would do this:
select concat(month(dob), '/', year(dob)) monthYear, count(*) cnt from t
group by monthYear
order by year(dob), month(dob)
However, in order to get the "missing dates" you'll have to generate data, because 01/1980 is not in any table, as far as I can see. Check this answer to see how.
how about this for sql-server
create table #temp
(
name varchar(50),
DOB datetime
)
insert into #temp values ('john', '2/21/1980')
insert into #temp values ('peter', '2/22/1980')
insert into #temp values ('lucy', '4/21/1980')
select convert(varchar(2), MONTH(DOB)) + '/' + Convert(varchar(4), YEAR(DOB)) as [MM/YYYY]
, count(*) as TotalCount
from #temp
group by convert(varchar(2), MONTH(DOB)) + '/' + Convert(varchar(4), YEAR(DOB))
drop table #temp
EDIT - This will get you all records for the dates included in the dates in the table. It will use the Min/Max Date in the table to get the date range, you then use this range to get the count of the birthdays in each month:
create table #temp
(
name varchar(50),
DOB datetime
)
insert into #temp values ('john', '2/21/1980')
insert into #temp values ('peter', '2/22/1980')
insert into #temp values ('lucy', '4/21/1980')
;with cte as
(
select min(DOB) as MinDate, max(DOB) as MaxDate
from #temp
union all
SELECT dateadd(mm, 1, t.MinDate), t.MaxDate
from cte t
where dateadd(mm, 1, t.MinDate) <= t.MaxDate
)
select convert(varchar(2), MONTH(c.MinDate)) + '/' + Convert(varchar(4), YEAR(c.MinDate))
, IsNull(t.TotalCount, 0) as TotalCount
from cte c
LEFT JOIN
(
SELECT convert(varchar(2), MONTH(DOB)) + '/' + Convert(varchar(4), YEAR(DOB)) as [MM/YYYY]
, count(*) as TotalCount
FROM #temp
group by convert(varchar(2), MONTH(DOB)) + '/' + Convert(varchar(4), YEAR(DOB))
) t
on convert(varchar(2), MONTH(C.MinDate)) + '/' + Convert(varchar(4), YEAR(C.MinDate))
= t.[MM/YYYY]
drop table #temp