I am trying to calculate the difference between dates but in order to separate them out correctly by month I am hoping to add new rows instead of have a column for each month. I need the following:
If the month of a start date [ss_strt_dtd] equal the month of the end date [ss_end_dtd] then nothing needs to happen.
However, if the the months differ then I need the start date to remain the same but the end date to be the first date of the new month. Then a new start date in the first of the month and the end date to remain the same.
Example:
January 15, 2018 - January 18, 2018 - Nothing needs to happen
January 28, 2018 - February 2, 2018 would need to be split into two
rows that look like this:
[ss_strt_dtd]01/28/2018 [ss_end_dtd]02/01/2018
[ss_strt_dtd]02/01/2018 [ss_end_dtd]02/02/2018
Any thoughts would be appreciated!
You can use UNION:
select ss_strt_dtd, ss_end_dtd from [S&S_Combined]
where year(ss_strt_dtd) = year(ss_end_dtd) and month(ss_strt_dtd) = month(ss_end_dtd)
union all
select ss_strt_dtd, DateSerial(year(ss_end_dtd), month(ss_end_dtd), 1) from [S&S_Combined]
where year(ss_strt_dtd) <> year(ss_end_dtd) or month(ss_strt_dtd) <> month(ss_end_dtd)
UNION ALL select DateSerial(year(ss_end_dtd), month(ss_end_dtd), 1), ss_end_dtd from [S&S_Combined]
where year(ss_strt_dtd) <> year(ss_end_dtd) or month(ss_strt_dtd) <> month(ss_end_dtd);
You can this with a set of queries that also will work if the timespan covers many months.
First a small query to return 10 numbers:
SELECT DISTINCT Abs([id] Mod 10) AS N
FROM MSysObjects;
Save this as Ten.
Then a query to return a the series of months in your date interval:
PARAMETERS
[DateStart] DateTime,
[DateEnd] DateTime;
SELECT
[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100+[Ten_3].[N]*1000+[Ten_4].[N]*10000+[Ten_5].[N]*100000+[Ten_6].[N]*1000000 AS Id,
[DateStart] AS DateStart,
[DateEnd] AS DateEnd,
DateAdd("m",[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100+[Ten_3].[N]*1000+[Ten_4].[N]*10000+[Ten_5].[N]*100000+[Ten_6].[N]*1000000,[DateStart]) AS DateMonth
FROM
Ten AS Ten_0,
Ten AS Ten_1,
Ten AS Ten_2,
Ten AS Ten_3,
Ten AS Ten_4,
Ten AS Ten_5,
Ten AS Ten_6
WHERE
(((DateAdd("m",
[Ten_0].[N]+[Ten_1].[N]*10+[Ten_2].[N]*100+[Ten_3].[N]*1000+[Ten_4].[N]*10000+[Ten_5].[N]*100000+[Ten_6].[N]*1000000,
[DateStart]))<=DateAdd("m",
DateDiff("m", [DateStart],DateAdd("d",-1,[DateEnd])),[DateStart]))
AND ((Ten_0.N)<=DateDiff("m",[DateStart],[DateEnd])\1)
AND ((Ten_1.N)<=DateDiff("m",[DateStart],[DateEnd])\10)
AND ((Ten_2.N)<=DateDiff("m",[DateStart],[DateEnd])\100)
AND ((Ten_3.N)<=DateDiff("m",[DateStart],[DateEnd])\1000)
AND ((Ten_4.N)<=DateDiff("m",[DateStart],[DateEnd])\10000)
AND ((Ten_5.N)<=DateDiff("m",[DateStart],[DateEnd])\100000)
AND ((Ten_6.N)<=DateDiff("m",[DateStart],[DateEnd])\1000000));
Save this as MonthsDateRange.
Finally, calculate the From and To dates for each month respecting the start and end date:
SELECT
MonthsDateRange.Id,
MonthsDateRange.DateStart,
MonthsDateRange.DateEnd,
Year([DateMonth]) AS [Year],
Month([DateMonth]) AS [Month],
IIf(DateDiff("m",[DateStart],[DateMonth])=0,
[DateStart],
DateSerial(Year([DateMonth]),Month([DateMonth]),1)) AS DateFrom,
IIf(DateDiff("m",[DateEnd],[DateMonth])=0,
[DateEnd],
DateSerial(Year([DateMonth]),Month([DateMonth])+1,1)) AS DateTo,
DateDiff("d",[DateFrom],[DateTo]) AS Days
FROM
MonthsDateRange;
Save this as DaysMonthsDateRange.
It will return something like this:
Note, that the query is designed to be able to return the months of the entire range of data type Date.
That is 118800 records from 100-01-01 to 9999-12-31.
Related
Hi I wanna get the next month in SQL server but what if the month is 12.
when i have date = '2016-10-04' then the next month will be date = '2016-11-04'.
I want to put this into this query :
if EXISTS(
select * from month
where id_Prod = #id_Prod
and datepart(month,DATEADD(month,1,_date)) = datepart(month,DATEADD(month,1,_date))
and datepart(YEAR,_date) = datepart(YEAR,#date)
);
you can try dateadd
declare #dt date = getdate()
select datepart(MM,dateadd(mm,1, #dt))
If the spec I've given in the comments is correct, you want something along the lines of:
if EXISTS(
select * from month
where id_Prod = #id_Prod
and _date >= DATEADD(month,DATEDIFF(month,'20010101',#date),'20010201')
and _date < DATEADD(month,DATEDIFF(month,'20010101',#date),'20010301')
);
The DATEADD,DATEDIFF pairs are just being used to generate "the 1st of next month" and "the 1st of the month after that", using arbitrary (fixed) dates to compute those. E.g. the first line computes how many whole months have occurred between 1st January 2001 and #date. It then adds that number of months onto 1st February 2001. This expression should therefore always generate the 1st of the month that comes after #date. The second pair does the same but adds the computed number onto 1st March instead.
You should also note that I'm not applying any functions to _date, so if there happens to be a useful index on that column, it should be usable for this query.
This seems pretty simple,
Get Previous date of current date
SELECT DATEADD(MONTH,-1,GETDATE()) AS PrviousDate
Get Next date of current date
SELECT DATEADD(MONTH,1,GETDATE()) AS NextDate
I have a table of the fiscal year for 100 years. i.e.
I am wanting to do add a column which shows the fiscal year that each week_ending_date belongs to. So in the table above week number 1, and week_ending_date 2013-10-05 would belong to fiscal year ending 2014.
In short I simply want each value in the added column to be the year part of week_ending_date where the next week_number is 52.
Here would be the pseudo code of what I am trying to achieve.
SELECT
Week_Ending_Date,
(SELECT NEXT VALUE FOR Week_Ending_Date (***but as only year***) FROM Fiscal_Calendar WHERE FC.Week_Number = 52)
FROM Fiscal_Calendar AS FC
JOIN Shipped_Container AS SC
ON SC.Fiscal_Week_Ending = FC.Week_Ending_Date
Bare in mind this has 100 years in the table and so I can't select the last value and makes using WHERE difficult (for me).
One way you can do this is by subtracting 7 * week number, taking the year and adding 1:
select 1 + year(dateadd(day, -7 * week_number, week_ending_date))
I've got two columns, one with a year (e.g. 2013, 2014) and one with a number of the month (e.g. 2, 3, 4).
Is there code that I could use to bring back the previous 12 months from my selected month? So if I selected my year as '2014' and my month as '9', I'd like to bring back the results going back to year '2013' and month '10'.
Is that possible without having a datetime field?
This should be possible. I would do this with "month" arithmetic. For instance, to get all dates since 2013-10, for selected month 2014-09:
select t.*
from table t
where year*12 + month >= 2014*12 + 9 - 12;
Getting the month for the current date is, obviously, straight forward, but I'm needing to get the month name with a different end date.
I need to get the month name with the start date of the month being the first Thursday after the first Wednesday of the month and the end date of the month being the first Wednesday of the following month. It's for an accounting thing, so I'm not going to argue with the spec!
e.g. for 2014, January would run from 9th Jan - 5th Feb, February would run from 6th February - 5th March, March would run from 6th March - 2nd April.
I would suggest that you create a table with your 'accounting months' in it, having a start date, end date and month name columns.
You could then query this to find the row where your date is between the start and end dates and return the month name. Putting this into a scalar function would then allow it to be reusable and relatively easily updated for next years months as well.
I think, as per Paddy's answer, a lookup table is the simplest thing to do. Here's one way to generate the rows for it:
; With Numbers(n) as (
select 4 union all select 5
), Months as (
select CONVERT(date,'20010104') as StartDt,CONVERT(date,'20010207') as EndDt,
DATENAME(month,'20010103') as Month
union all
select DATEADD(week,n1.n,StartDt),DATEADD(week,n2.n,EndDt),
DATENAME(month,DATEADD(week,n1.n,StartDt))
from Months,Numbers n1,Numbers n2 --Old-skool join, just for once
where DATEPART(day,DATEADD(week,n1.n,StartDt)) between 2 and 8 and
DATEPART(day,DATEADD(week,n2.n,EndDt)) between 1 and 7 and
StartDt < '21000101'
)
select * from Months option (maxrecursion 0)
(CW since this is effectively just an extension to Paddy's answer but I don't want to edit their answer, nor is it suitable for a comment
my user table is as follows:
birhtMonth: int
dayOfBirthday: int
HireDate: Date
REQUIREMENT: i want to get all upcoming birthdays and hire dates (day/month year is excluded here) in next 6 months, putting in consideration that for current month the day should be greater than today, so here's what i did:
#Query("from User u where ( (u.birthMonth in (8,9,10,11,12,1)) or (month(u.hireDate) in (8,9,10,11,12,1)) ) and u.company = :company")
this gets all upcoming birthdays & hire dates in next six months but it gets birthdays & hire dates in this month for days before & after current day, and it should only get results > current day and ignore results < current day in this month.
EXAMPLE:
today's date is 8/3/2013, if there's birthday with birthMonth=8 and dayOfBirth=3 or 2 or 1 it should be ignored only dayOfBirth > 3 in current month is considered, also if there's hirDate like:
2011-08-01
2012-08-02
2012-08-03
they should be ignored too, please advise how to solve this in sql or hql.
Your hireDate is of type Date, so use a date comparison and use between such as:
(hireDate between :toDayParam and :sixMonthLaterParam)
for birthDate, you can compare with lpad(birthMonth, 2, 0) + lpad(birthDate, 2, 0) but you shall care about whether six month later is in next year or current year.
I think your looking for the DATE functions. They can greatly help you out here. Specifically the DATEADD function. Take a look at the code I made here.
SELECT * FROM dbo.product
WHERE dbo.product.stockDate > GETDATE()
AND dbo.product.stockDate < GETDATE() + DATEADD(month, 6, dbo.product.stockDate)
AND dbo.product.expirationDate > GETDATE()
AND dbo.product.expirationDate < GETDATE() + DATEADD(month, 6, dbo.product.expirationDate)
This will guarantee that the stockDate and the expirationDate are greater than the current date and less than the current date + 6 mo. DATEADD works as follows DATEADD(-what you want to increment by-, -how much you want to increment-, -date to add to-).