Unique Start and End Effective Date Scenario - sql-server

Okay, so I have an sql query that I run on a weekly basis that now needs to be ran on a monthly basis. In the query I have a start effective date and an end effective date for the date range the report should pull. Now what I want to do is a formula for the start and end date.
The start effective date I want to be previous month from today's date and then the last Monday of the previous month.
The end effective date I want to be the max modified date from my product details table.
I know what I am looking for but I am unsure how to write this in code? Thanks!!!

This should do the trick:
DECLARE #Today date = convert(date, getdate());
DECLARE #Monday tinyint = 1;
DECLARE #LastDayOfMonth date = DATEADD(d,-1,DATEADD(month, DATEDIFF(month, 0, #Today), 0));
DECLARE #LastWeekDayOfMonth int = datepart(weekday,DATEADD(d,-1,DATEADD(month, DATEDIFF(month, 0, #Today), 0)));
SELECT DATEADD(d, #Monday-#LastWeekDayOfMonth+1, #LastDayOfMonth) AS LastMonday

try this
declare #dt datetime
set #dt=GETDATE()
select DATEADD(WEEK,DATEDIFF(WEEK,0,DATEADD(DAY,DATEPART(DAY,dateadd(m,-1,GETDATE())),dateadd(m,-1,GETDATE()))), 0) StartDate

Related

Declaring a date as being the last month day of another date

I'm trying to write a financial report on our SAP B1 system using SQL Server Studio.
In my report I want the information to be calculated on a month to month basis. In my report I have #start date as #Startofcurrentfinancialyear, and my end as DD+30 (because there are 31 days in the month) However I am wanting to have mm+1 and dd-1 to bring me to the last day in the month.
I plan on changing the report for each month to give me the following.
MM+1 (for month 2) and MM+2 - DD 1 to give me the date range for month 2 etc.
Currently, I can make this go based on the following: MM+0, DD+30, then going ahead doing DD+60 etc and calculating for each month how many days they are, but this will give me problems with leap years.
DECLARE #Start DATETIME = DATEADD(MM,-0,#StartOfCurrentFinancialYear)
DECLARE #End DATETIME = DATEADD(DD,+30,#StartOfCurrentFinancialYear)
I expect to be able to define a month for each section and give the last day of the defined month based on the parameters given above.
If you want the end of month, then in all supported versions of SQL Server, you can do:
DECLARE #Start DATETIME = DATEADD(MONTH, -0, #StartOfCurrentFinancialYear);
DECLARE #End DATETIME = EOMONTH(#StartOfCurrentFinancialYear);
If you are using an unsupported version, you can do date arithmetic:
DECLARE #End DATETIME = DATEADD(day, -1,
DATEADD(month, 1,
DATEADD(day,
1 - DAY(#StartOfCurrentFinancialYear),
#StartOfCurrentFinancialYear
),
)
);
This does the following calculation:
Innermost subquery dateadd() moves to the first day of the month.
Middle subquery adds one month.
Outer query subtracts one day.
If you want start of the month and end of the month you can get it by using DateAdd function like :
DECLARE #Start DATETIME = DATEADD(DAY, (DAY(GETDATE()) * -1) + 1, GETDATE())
DECLARE #End DATETIME = DATEADD(MONTH,1,DATEADD(DAY, DAY(GETDATE()) * -1, GETDATE()))
SELECT #Start, #End
you can replace GETDATE() with your date variable so after your replacement the code should be something like this :
DECLARE #StartOfCurrentFinancialYear AS DATE = '31/aug/2019'
DECLARE #Start DATETIME = DATEADD(DAY, (DAY(#StartOfCurrentFinancialYear) * -1) + 1, #StartOfCurrentFinancialYear)
DECLARE #End DATETIME = DATEADD(MONTH,1,DATEADD(DAY, DAY(#StartOfCurrentFinancialYear) * -1, #StartOfCurrentFinancialYear))
SELECT #Start, #End

Adding fixed time onto datetime gives unexpected results

I have a query that takes two datetime variables (Start date and end date) and appends two differing fixed times to allow for a business trading time offset.
An example of a test query using this logic is:
DECLARE #startdate datetime;
DECLARE #enddate datetime;
SET #startdate = convert(datetime,'2017-01-01')
SET #enddate = convert(datetime,'2017-01-02')
SELECT *
FROM ig_Business..Check_Item_Detail CID (NOLOCK)
JOIN ig_business..Check_Sales_Detail CSD (NOLOCK) ON CSD.transaction_data_id = CID.transaction_data_id
WHERE csd.tendered_date_time BETWEEN DATEADD(m, DATEDIFF(m, 0, convert(date, #STARTDATE)), 0) + '06:00:00'
AND DATEADD(m, DATEDIFF(m, 0, convert(date, #ENDDATE)), 0) + '05:59:59'
However, the result set for this query is empty, and I am unsure why, because when I run
select DATEADD(m, DATEDIFF(m, 0, convert(date, #STARTDATE)), 0) + '06:00:00'
i get back a seemingly valid datetime : 2017-01-01 06:00:00.000
An example of what is returned when I remove the time restriction:
i get back a seemingly valid datetime : 2017-01-01 06:00:00.000
You're not.
You're getting back a date that has been automatically cast to a string, and have glued another string on the end, giving you a string that looks like a datetime.
If you want to add something to the date, use another dateadd(). This will give you a BETWEEN comparison with actual datetimes.
Right now you are doing a "between" with a datetime and a string.
I'm surprised it doesn't throw an error.
If 2012+, you can use format() to append a time to a date/datetime value
Example
Declare #startdate date = '2017-01-01'
Select format(#startdate,'yyyy-MM-dd 06:00:00')
Returns
2017-01-01 06:00:00
This format() can be included in your where
...
Where SomeDateTime between format(#startdate,'yyyy-MM-dd 06:00:00')
and format(#enddate,'yyyy-MM-dd 17:00:00')

How to get date from yyyy-mm-dd to yyyy-mm-dd in SQL?

I want to get date from yyyy-mm-dd to yyyy-mm-dd in SQL.
Example: I have two parameter #startdate : 2015-12-28 and #enddate : 2016-01-02, and database in SQLServer, datatype is varchar(10)
DATE_ORDER
28-12-2015
30-12-1996
29-12-2016
30-12-1997
24-12-2015
27-12-1993
03-01-2016
01-01-1992
02-01-2016
etc...
Ok,now I want to get data from #startdate : 2015-12-28 and #enddate : 2016-01-02. I use SELECT * FROM TABLE_X WHERE DATE_ORDER >= #startdate AND DATE_ORDER <= #enddate . But the results are not what I expected. Here are the results I want
28-12-2015
30-12-1996
29-12-2016
30-12-1997
01-01-1992
02-01-2016
I think to solve this problem, I need to do two things :
First, get date range from #startdate to #enddate , in here 28/12/2015, 29/12/2015, 30/12/2015, 31/12/2015, 01/01/2016, 02/01/2016.
The second: get the date in database same in range 28/12, 29/12, 30/12, 31/12, 01/01, 02/01, ignoring the year.
Can you give me some ideas about this ?
Your actual format is "105-italian" find details here.
You can convert your existing VARCHAR(10)-values with this line to real datetime
SELECT CONVERT(DATETIME,YourColumn,105)
Next thing to know is, that you should not use BETWEEN but rather >=StartDate AND < NakedDateOfTheFollowingDay to check date ranges
So to solve your need Get date-range from 2015-12-28 to 2016-01-02 you might do something like this:
DECLARE #Start DATETIME={d'2015-12-28'};
DECLARE #End DATETIME={d'2016-01-02'};
SELECT *
FROM YourTable
WHERE CONVERT(DATETIME,YourDateColumn,105)>=#Start AND CONVERT(DATETIME,YourDateColumn,105)<#End+1
Attention Be aware, that the conversion lets your expression be not sargable. No index will be used.
Better was to store your date as correctly typed data to avoid conversions...
Try this query
SET DATEFIRST 1
DECLARE #wk int SET #wk = 2
DECLARE #yr int SET #yr = 2011
--define start and end limits
DECLARE #todate datetime, #fromdate datetime
SELECT #fromdate = dateadd (week, #wk, dateadd (YEAR, #yr-1900, 0)) - 4 -
datepart(dw, dateadd (week, #wk, dateadd (YEAR, #yr-1900, 0)) - 4) + 1
SELECT #todate = #fromdate + 6
;WITH DateSequence( Date ) AS
(
SELECT #fromdate AS Date
UNION ALL
SELECT dateadd(DAY, 1, Date)
FROM DateSequence
WHERE Date < #todate
)
--select result
SELECT * FROM DateSequence OPTION (MaxRecursion 1000)
So, after the 2nd or 3rd edit, it slowly becomes clear, what you want (i hope).
So you REALLY WANT to get the dates with the year beeing ignored.
As someone pointed out already, date-values are stored internally not as string, but as internal datatype date (whatever that is in memory, i don't know).
If you want to compare DATES, you cannot do that with ignorance of any part. If you want to, you have to build a NEW date value of day and month of given row and a hard coded year (2000 or 1 or whatever) for EVERY row.
SELECT * FROM TABLE_X WHERE convert(date,'2000' + substring(convert(char(8),convert(datetime, 'DATE_ORDER', 105),112),5,4),112) >= #startdate AND convert(date,'2000' + substring(convert(char(8),convert(datetime, 'DATE_ORDER', 105),112),5,4),112) <= #enddate
If your startdate and enddate go OVER sylvester, you have to do 2 queries, on from startdate to 1231, one from 0101 to enddate.

How to calculate difference between two dates in workdays

I need to calculate difference in workdays between two dates. Is there a built in function for this in SQL Server? Can someone please provide an example on how to do this?
Here is something I wrote quickly. Just encapsulate it into a function or whatever you need.
declare #StartDate datetime
declare #EndDate datetime
declare #TotalDiff int
declare #NumberOfWeekends int
SET #StartDate = '3/12/2013'
SET #EndDate = '3/22/2013'
SET #NumberOfWeekends = 0
SET #TotalDiff = DATEDIFF(d,#StartDate, #EndDate)
If #TotalDiff > 7
SET #NumberOfWeekends = #TotalDiff / 7
else if DATEPART(dd, #EndDate) < DATEPART(DD, #StartDate)
SET #NumberOfWeekends = 1
select (#TotalDiff - 2*#NumberOfWeekends) as TotalWorkDays
No, there is nothing built in to SQL Server to directly give you number of working days between two dates, however there are a few built-in functions which will enable you to write one.
Firstly, a few caveats
The world cannot agree what a "Working Day" is. For most of us it's Saturday and Sunday. For most of the Middle East it's Friday & Saturday (with Sunday being a normal working day)
The world most certainly cannot agree on what constitutes a public holiday, which are almost always considered non-working days.
You have not specified how you would like to handle these cases so lets make some assumptions:
Saturday and Sunday will be non-working days
Public holidays will not be taken into acount
Now, determining if a particular days is saturday or sunday in sql is easy, given a #date of type DateTime:
IF DATENAME(dw,#date) IN ('Saturday','Sunday')
With that in mind, given a start and end date, you can just count incrementally from #startDate to #endDate
DECLARE #startDate DATETIME = '2013-01-01'
DECLARE #endDate DATETIME = '2013-01-20'
DECLARE #currDate DATETIME = #startDate
DECLARE #numDays INT = 0
WHILE #currDate<#endDate
BEGIN
IF DATENAME(dw,#currDate) NOT IN ('Saturday','Sunday')
SET #numDays = #numDays + 1
SET #currDate = DATEADD(day,1,#currDate)
END
SELECT #numDays
Note: This is non-inclsive so wont count #endDate. You could change it to be inclusive by changing WHILE #currDate<#endDate to WHILE #currDate<=#endDate
My solution does not count the #EndDate, so if you need to change that, just add 1 to #d2.
First, I calculate the number of days from an "initial" day (which happens to be 1/1/1900, a Monday) to #StartDate and #EndDate:
DECLARE #d1 int = DATEDIFF(Day, 0, #StartDate);
DECLARE #d2 int = DATEDIFF(Day, 0, #EndDate);
Then, the total number of days between #StartDate and #EndDate is:
#d2 - #d1
From this, I substract the number of Sundays and the number of Saturdays in the interval, each calculated as a difference simlar to the total days, but now for whole weeks (7 days). To get the number of whole weeks, I use integer division by 7 and the fact that the "initial" day (0) is a Monday. The number of Sundays in the interval is
#d2/7 - #d1/7
and the number of Saturdays is
(#d2+1)/7 - (#d1+1)/7
Putting all together, my solution is:
DECLARE #StartDate DATETIME = '20180101'
DECLARE #EndDate DATETIME = '20180201'
DECLARE #d1 int = DATEDIFF(Day, 0, #StartDate)
DECLARE #d2 int = DATEDIFF(Day, 0, #EndDate)
SELECT #d2 - #d1 - (#d2/7 - #d1/7) - ((#d2+1)/7 - (#d1+1)/7) AS workdays

Create "BETWEEN/AND"-capable DATETIMEs from given DATETIME

I want to create two DATETIME variables I can use to check with BETWEEN AND when given just one DATETIME in a stored procedure on SQL Server 2008.
So, when I get 2012/12/31 15:32:12 as input, I want to generate two new variables out of that, being #from = 2012/12/31 00:00:00 and #to = 2012/12/31 23:59:59.
These two variables are used to check if the records lie between them - that is, are on the same day as the input date.
I fooled around using CAST and CONVERT, but I don't really konw how to manipulate the dates in the way I want.
Should I do this another way? Or are there functions I'm not aware of?
Now it is version independedt
declare #from datetime, #to datetime
SET #from = convert(varchar, convert(datetime, '2012/12/31 15:32:12', 111), 112)
SET #to = DATEADD(day, 1, #from)
select * from yourtable where test date >= #from AND date < #to
You can;
declare #input datetime = '2012/12/31 15:32:12'
declare #from datetime = dateadd(day, 0, datediff(day, 0, #input))
declare #to datetime = dateadd(second, -1, dateadd(day, 1, #from))
>>>
2012-12-31 00:00:00.000 2012-12-31 23:59:59.000
Be careful of accuracy on your #to. 23:59:59.001 is a valid date but won't show up in your range if you subtract an entire second.
It is more common to set your #from and then use < #from + 1 instead of BETWEEN. (The plus adds whole days in SQL).
First convert your input date to a varchar using the appropriate date format(111 in this case), For the to date, append the midnight hour
Then cast your varchar back to datetime.
Example :
SELECT #from = CAST(CONVERT(VARCHAR(10), GETDATE(), 111) AS DATETIME)
,#to = CAST(CONVERT(VARCHAR(10), GETDATE(), 111)+' 23:59:59:997' AS DATETIME)
Here is a useful chart of datetime formats with brief explanations.
http://www.sql-server-helper.com/tips/date-formats.aspx

Resources