SQL Replace and Update a Datetime string "before a certain date" - sql

I have a data field Date in the format of yyyyMMdd string (varchar). How do I replace everything before a certain date, say 20180201, to certain month, say March 2018!? Only the year and the month are changed, keep the day.
Example: A string 20160913 will be changed to 20180313, but 20180224 will be kept as it was, because it was after 20180201.

Convert that string to a date to search for the greater than a date, and use substring to extract the day part to build the new date string.
declare #NewYear varchar(4) = '2018'
declare #NewMonth varchar(2) = '03'
declare #PivotDate date = '2018-02-01'
update myTable set MyField = #NewYear + #NewMonth + substring(MyField, 6, 2)
where convert(date, MyField, 112) > #PivotDate

I would recommend doing this as:
declare #NewYear varchar(4) = '2018';
declare #NewMonth varchar(2) = '03';
declare #PivotDate date = '2018-02-01';
update myTable
set MyField = #NewYear + #NewMonth + right(MyField, 2)
where myfield < convert(varchar(255), #PivotDate, 112);
The important part of this solution is the where clause. In particular, there is no function call on myfield which allows an index to be used. An expression that allows an index is called sargable.

I would recommend to doing this, because if #NewMonth < February, then it can be a problem.
declare #NewYear varchar(4) = '2018'
declare #NewMonth varchar(2) = '02'
declare #PivotDate date = '2018-02-01'
update myTable set MyField = DATEADD(day,(right(MyField, 2)-1),cast((#NewYear + #NewMonth + '01') as date))
where convert(date, MyField, 112) > #PivotDate
Thank You!

Related

SQL Select statement, change Format mmddyy to dd-mon-yyyy with convert

I want to select field opendate mmddyy data type decimal(6,0) to dd-mon-yyyy. How do I modify this statement?
select convert(varchar(10),M.opendate, 106)
FROM All.Customer M
The above results in the following error:
[SQL0204] CONVERT in *LIBL type *N not found
You can try this:
DECLARE #InputDate VARCHAR(8)
SET #InputDate = '073019'
DECLARE #InputYear VARCHAR(4)
DECLARE #InputMonth VARCHAR(2)
DECLARE #InputDay VARCHAR(2)
SET #InputYear = '20' + SUBSTRING(#InputDate, 5, 2)
SET #InputMonth = LEFT(#InputDate, 2)
SET #InputDay = SUBSTRING(#InputDate, 3, 2)
DECLARE #OutputDate DATE
SET #OutputDate = #InputYear +'-'+ #InputMonth +'-'+ #InputDay
SELECT CONVERT(VARCHAR(15), #OutputDate, 106)
Still you should know how to define the first 2 digits of the year. I have used '20' as default.

How to get the last day of the month using only month and year?

I want to find out how to find the last day of the month if I only have a year and a month (and no day).
I tried using EOMONTH(), but this function needs the date consisted of year, month and day. I can only use year and month values.
How do I do something like this?
If you are using Sql Server 2012 then I'd use DATEFROMPARTS.
DECLARE #year SMALLINT = 2016
,#month TINYINT= 02
SELECT EOMONTH(DATEFROMPARTS(#year,#month,1))
You can still use EOMONTH even if you do not have a day of the month, just use the first of the month as the day of month is not significant in the input.
-- incoming parameters (assuming string but could be int and you could cast them)
DECLARE #month VARCHAR(2) = '11', #year VARCHAR(4) = '2016'
DECLARE #date DATETIME
DECLARE #lastDayOfMonth INT
SELECT #date = CONVERT(date, #year + #month + '01', 101) -- this first part is what you know (year + month), the 01 is just the first day of whatever month appended so the date is valid
-- get the last day of month as a date using EOMONTH and then use DATEPART to get the day of the month
SELECT #lastDayOfMonth = DATEPART(dd, EOMONTH(#date))
SELECT #lastDayOfMonth -- your output on the screen
VARCHAR TYPES
DECLARE #D DATE
DECLARE #YearV VARCHAR(4) = '2016'
DECLARE #MonthV VARCHAR(2) = '12'
SET #D = DATEADD(dd,-1,DATEADD(mm,1,CAST(#YearV + #MonthV + '01' AS DATE)))
SELECT #D
INT TYPES
DECLARE #D DATE
DECLARE #Year INT = '2016'
DECLARE #Month INT = '11'
SET #D = DATEADD(dd,-1,DATEADD(mm,1,CAST(CAST(#Year AS VARCHAR(4)) + CAST(#Month AS VARCHAR(2)) + '01' AS DATE)))
SELECT #D
COMBINED TYPES
some SUBSTRING code depending on the format... :)

Date calculation in variable

I'm doing my best to set a date variable so I can compare it later. I would like something that basically says:
If the current day-of-month is less than 11, then date is 10th of LAST month
If the current day-of-month is greater-than-or-equal-to 11, then date is 10th of THIS month
Date is 11/6/2012 expected output:
#PODate = 10/10/2012
Date is 11/16/2012 expected output:
#PODate = 11/10/2012
Currently all I have is this:
DECLARE #PODate as DATETIME
Set #PODate = Convert(varchar(8),GetDate(),1)
Any tips or help would be greatly appreciated. Thank you!!
Trying to keep it as straightforward as possible:
declare #PODate datetime
select #PODate = DATEADD(month,
DATEDIFF(month,'20010110',CURRENT_TIMESTAMP) +
CASE WHEN DATEPART(day,CURRENT_TIMESTAMP) <= 10 THEN -1 ELSE 0 END,
'20010110')
The surrounding DATEADD/DATEDIFF pair are being used to normalize the date to the 10th of the current month. We then use a small CASE expression to subtract a month if the day is less than or equal to the 10th.
Whatever solution you pick, please try to avoid ones that do it as string manipulation. The usual cause of datetime related bugs in SQL is when people treat dates as strings. Keeping the data types appropriately is usually the best way to prevent these issues.
There are, admittedly, 2 strings in my solution, but these are fixed constant strings (all that matters is that they're both for the same year and month, and the second one is for the 10th of the month) and are in an unambiguous format.
Try this: SQL Fiddle
DECLARE
#PODate as DATETIME,
#LastMonth as DateTime,
#strDate as Varchar(50)
set #PODate = '11/16/2012'
set #LastMonth = DATEADD(MONTH, -1, #PODate)
if(DAY(#PODate) < 11)
SET #strDate = CAST(MONTH(#LastMonth) AS VARCHAR)+'/10/'+CAST(YEAR(#LastMonth) AS VARCHAR)
else
SET #strDate = CAST(MONTH(#PODate) AS VARCHAR)+'/10/'+CAST(YEAR(#PODate) AS VARCHAR)
Select CAST(#strDate AS DateTime)
DECLARE #PODate date = '20121116'
SELECT CASE WHEN DATEPART(day, #PODate) < 11 THEN DATEADD(mm, DATEPART(mm, GETDATE()) - DATEPART(mm, #PODate) - 1, DATEADD(day, 10 - DATEPART(day, #PODate), #PODate))
ELSE DATEADD(mm, DATEPART(mm, GETDATE()) - DATEPART(mm, #PODate), DATEADD(day, 10 - DATEPART(day, #PODate), #PODate)) END
Demo on SQLFiddle
DECLARE #currDate DATE = dbo.GetDate()
DECLARE #day INT = day(#currDate)
DECLARE #month INT
DECLARE #year INT
DECLARE #PODate DATE
IF( #day >= 11)
BEGIN
SET #month = month(#currDate)
SET #year = year(#currDate)
END
ELSE BEGIN
SET #month = month(dateadd(m,-1,#currDate))
SET #year = year(dateadd(m,-1,#currDate))
END
SET #PODate = convert(DATE,'10-' + convert(VARCHAR,#month) + '-' + convert(VARCHAR,#year))
PRINT #PODate
if #currDate = '11-jan-2013' , #PODate will be '10-jan-2013', and if #currDate = '07-jan-2013' , #PODate will be '10-Dec-2012'

Working out a date from a single month number SQL

Got 2 parameters #yr and #period, #period is just the month number so July would equal 7 for example.
In my stored procedure table I've got a column called Date which is just a standard datetime field. I need a where clause to work out all dates greater than the current period minus 1 year so if #period = 7 and #yr = 2012 I want the where clause to return all dates greater than '01-07-2011' (UK date format) how can I achieve this with just the 2 numbers from #period and #yr.
WHERE <br>
Date >= '01-07-2011'
You could
Date >= dateadd(month, #period-1, dateadd(year, #yr-1900, 0))
where year(date)>year(getdate()-1) and month(date)>#period
If you want the expression sargable, convert it to datetime:
declare #year int = 2012
declare #month int = 7
select
...
where [Date] >= convert(datetime, convert(varchar(4), #year)
+ right('0' + convert (varchar(2), #month), 2)
+ '01')
After seeing Alex K.'s answer, you might even do this:
dateadd(month, #month - 1 + (#year-1900) * 12, 0)
For the best performance you should do something like this:
declare #yr int = 2012
declare #period int = 7
select ...
from ....
WHERE date >= dateadd(month, (#yr - 1901) * 12 + #period - 1, 0)
We can do it in may ways
try it
DECLARE #a VARCHAR(20),
#b VARCHAR(10),
#c varchar(4)
SET #b='may' /*pass your stored proc value */
SET #c='2011'
SET #a='01'+#b+#c
SET DATEFORMAT YDM
SELECT CAST(#a AS DATE)
FOR uk formate
SELECT CONVERT(char,CAST(#a AS DATE),103)
Just t make sure you compare against an entire date, one solution I'd offer is:
Select *
from TheTable
where date> DateAdd(Year,-1, convert(datetime, '01/'+convert(varchar,#period)+'/' + convert(varchar,#yr)))
To account for regional format differences in SQL Server 2012:
Select *
from TheTable
where date> DateAdd(Year,-1, DateFromParts(#year,#period,1))
For pre-2012:
Select *
from TheTable
Where Date > DateAdd(day, 0, DateAdd(month, #period-1, DateAdd(year, (#yr-1900)-1,0)))
The #yr-1900 is maintained to illustrate the computation of the base date offset from 1900, then subtracting 1 for the one-year-off date computation

dateformat not as expected

I have the following function below.
It returns a date like Feb 29 2012 10:00PM. Is there a way to make it return the format as 2/29/2012 10:00PM
CREATE FUNCTION scrubDateString
(
-- Add the parameters for the function here
#inputDate varchar(150)
)
RETURNS DATETIME
AS
BEGIN
-- Declare the return variable here
DECLARE #Result DATETIME
-- Add the T-SQL statements to compute the return value here
DECLARE #tmpDate datetime
SET #Result = null
IF (ISDATE(#inputDate)=1)
BEGIN
SET #Result = DATEADD(HH, 5, #inputDate)
END
-- Return the result of the function
RETURN #Result
END
The function itself is returning a Date and time, "Feb 29 2012 10:00PM" and "2/29/2012 10:00AM" are merely string representations of that date (I am assuming that the AM and PM switch are not relevant to the question and are just a mistake). IF you want to format the date as a particular string look at the CONVERT function. e.g:
DECLARE #Date DATETIME
SET #Date = scrubDateString(#YourString)
SELECT CONVERT(VARCHAR, #Date, 101) + ' ' + RIGHT(CONVERT(VARCHAR, #Date, 0), 7) [Date]
Although I'd strongly advise leaving your date as a date, and doing any formatting on the application side if at all possible. If I have assumed wrong about the AM PM switch you could alter the code above to the following:
DECLARE #Date DATETIME
SET #Date = scrubDateString(#YourString)
IF (DATEPART(HOUR, #Date) > 12)
BEGIN
SET #Date = DATEADD(HOUR, -12, #Date)
END
SELECT CONVERT(VARCHAR, #Date, 101) + ' ' + RIGHT(CONVERT(VARCHAR, #Date, 0), 7) [Date]
If you want to format a DateTime you will need to return it as VARCHAR instead of as a date. If you declare a FUNCTION to return DateTime then it will always return a DateTime formatted in the standard SQL way.
You can return it as a string by using the sql CONVERT function:
RETURN CONVERT(varchar(500), #Result, 101)
A list of formats can be found on msdn. If you want a different format then you need to do something like what's discussed in this question
just change\add this:
SET #Result = DATEADD(HH, 5, #inputDate)
SET #Result = CONVERT(VARCHAR(10), #Result , 101) + ' ' + RIGHT(CONVERT(VARCHAR, GETDATE(), 100), 7)
you can make it on one line, of course, just did on 2 for clarity
forgot to add that you need to change the return variable to varchar, instead of datetime.
If you cant do that, maybe you can add the convert to the places that are calling the function (which would be worst, for sure)