I have a user defined function that looks like this;
ALTER FUNCTION [dbo].[func_format_date]
(
-- Add the parameters for the function here
#input VARCHAR(6)
)
RETURNS VARCHAR(6)
AS
BEGIN
-- Declare the return variable here
DECLARE #mon CHAR(2),
#day char(2),
#year char(4),
#output DATETIME
-- Return the result of the function
SELECT #mon = LEFT(#input, 2), #day =SUBSTRING(#input, 3,2), #year = RIGHT(#input,4)
SELECT #output = #year+#mon+#day
RETURN CONVERT(VARCHAR(6), #output, 12)
END
The goal is to be able to pass in a date say “022019” (mmddyy) and the function will format the date as such “190220” (yymmdd). This seems to work only sometime as if I pass in the following dates see the results below; it seems to be inconsistent in terms of the dates it accepts vs the dates that throw an error
022019 (Works fine)
032019 (Works fine)
021019 (Results in a “The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.” error)
030519 (Results in a “The conversion of a varchar data type to a
datetime data type resulted in an out-of-range value.” error)
I have checked to ensure the default language is correct and it is. Can someone help me to figure this out?
First, the reason for this error - your #input parameter is varchar(6), you read 1st and 2nd characters as month, 3rd and 4th as day, and 3rd, 4th, 5th and 6th as year. When #input is equal to '021019', your year will be 1019 and this is outside the datetime datatype range.
Second, change your logic:
make your #input parameter varchar(8)
generate datetime value using DATETIMEFROMPARTS() function if you have four digit year
If you want to fix your function, next may help:
ALTER FUNCTION [dbo].[func_format_date]
(
#input VARCHAR(6)
)
RETURNS VARCHAR(6)
AS
BEGIN
-- Declare the return variable here
DECLARE
#mon VARCHAR(2),
#day VARCHAR(2),
#year VARCHAR(2),
#output DATETIME
-- Return the result of the function
SELECT
#mon = SUBSTRING(#input, 1, 2),
#day = SUBSTRING(#input, 3, 2),
#year = SUBSTRING(#input, 5, 2)
-- Generate datetime value
SELECT #output = CONVERT(datetime, #year + #mon + #day, 12)
-- or if your dates are after 2000
--SELECT #output = DATETIMEFROMPARTS(2000 + #year, #mon, #day, 0, 0, 0, 0)
-- Return value
RETURN CONVERT(VARCHAR(6), #output, 12)
END
You Can Simply your function using below Stmt.
If no Date Validation Required you can interchange values.
select RIGHT(#input,2) + LEFT(#input, 2) + SUBSTRING(#input, 3,2)
If Date Validation Required use below.
select Convert(varchar, Convert(datetime, LEFT(#input, 2) + '/' + SUBSTRING(#input, 3,2) + '/' + RIGHT(#input,2), 1), 12)
Related
I have a function that returns a datetime2.
...
MS_VatToDate (#vYEAR smallint, #vMONTH smallint, #vDAY smallint)
...
DECLARE #VatDate DATETIME2;
DECLARE #VatDateText VARCHAR(11);
SET #VatDateText = CAST(#vYEAR AS VARCHAR(4)) + '-' +
CAST(#vMONTH AS VARCHAR(2)) + '-' +
CAST(#vDAY AS VARCHAR(2));
SET #VatDate = CONVERT(DATETIME2, #VatDateText, 126);
RETURN(#VatDate);
When I specify data it works just fine, but when I specify some range I get an error.
Conversion failed when converting date and/or time from character string.
The same thing happened when I tried to apply this function for whole database, but at start I'm getting correct result and then at the end it's the same error.
Why are you writing your own function?
SQL Server offers datefromparts(), so you an just write:
select datefromparts(2018, 11, 30)
If you want a datetime2:
select convert(datetime2, datefromparts(2018, 11, 30))
Or datetime2fromparts():
select datetime2fromparts(2018, 11, 30, 0, 0, 0)
Support for SQL Server 2008 R2 ends in July, 2019, so you should update before support ends.
In the older system, you can convert without a format -- unless your default date format is YDM:
set #VatDateText = cast(#vYEAR as varchar(4))+'-'+cast(#vMONTH as varchar(2))+'-'+cast(#vDAY as varchar(2));
set #VatDate = convert(datetime2, convert(date, #VatDateText));
I suppose you can use ISDATE function prior to conversion:
DECLARE #VatDate datetime2;
DECLARE #VatDateText varchar(11);
SET #VatDateText = CAST(#vYEAR as varchar(4)) + '-' + CAST(#vMONTH as varchar(2)) + '-' + CAST(#vDAY as varchar(2));
IF ISDATE(#VatDateText) = 1
SET #VatDate = convert(datetime2, #VatDateText, 126);
ELSE
PRINT #VatDateText + ' is invalid';
SELECT /* RETURN */ #VatDate;
If you can't use DATEFROMPARTS (it is available since SQL Server 2012), remove the dashes and cast the string directly. '20181130' will be successfully converted to date, regardless of your locale and dates settings. In this case it could also be that you have single digit month/day in your data and the constructed string is not valid, so add leading zeroes.
declare #VatDate datetime2;
declare #VatDateText varchar(11);
set #VatDateText = cast(#vYEAR as varchar(4))+right('0' +cast(#vMONTH as varchar(2)), 2)+right('0' + cast(#vDAY as varchar(2)), 2);
set #VatDate = cast(#VatDateText as datetime2);
return(#VatDate);
declare
#pm_WeekEndDate DATETIME,
#lp_Day VARCHAR(10),
#intDate DATETIME
set #pm_WeekEndDate = MONTH(#pm_WeekEndDate)
set #lp_Day = day(#pm_WeekEndDate)
set #intDate = (#pm_WeekEndDate & #lp_Day)
This code should take month january then = 1 because other table has all in numbers like month 1 to 12 and day 1 to 7.
But I am getting this error:
Msg 402, Level 16, State 1, Procedure PRO, Line60
The data types datetime and varchar are incompatible in the '&' operator.
This is purely a guess by on extremely vague details and having this kind of poor table design in the past. Is something like this what you are looking for?
declare #pm_WeekEndDate DATETIME = getdate()
select #pm_WeekEndDate
declare #DateVal char(4)
select #DateVal = right('00' + convert(varchar(2), MONTH(#pm_WeekEndDate)), 2) + right('00' + convert(varchar(2), DAY(#pm_WeekEndDate)), 2)
select #DateVal
Please notice that you can't have the result be a date because it doesn't make sense. I am guessing that your table has dates stored as either strings or ints??
How can I convert, for example, ddmmyyyy which is a varchar(8) to date format(dd/mm/yyyy)?
I have a stored procedure which accepts a date varchar(8) parameter.
I want to convert it to date format before inserting into database.
I tried to use
INSERT INTO mytable(createdDate) VALUES (CONVERT(date, CONVERT(varchar(8), #date), 106));
An error:
Conversion failed when converting date and/or time from character string.
createdDate column is type : date
ddmmyyyy is not a valid date format. You need to first make that string into something that can be parsed as a DATE / DATETIME. The quickest way might be to simply SUBSTRING the pieces into a mm/dd/yyyy format. That does convert successfully. But you have a VARCHAR(8). So you either need to increase that to be VARCHAR(10) (or better yet, just CHAR(10)), or declare a local variable to hold the altered value.
For example:
DECLARE #Date VARCHAR(8); -- input parameter
SET #Date = '25032014';
DECLARE #Date2 CHAR(10);
SET #Date2 = SUBSTRING(#Date, 3, 2)
+ '/' + SUBSTRING(#Date, 1, 2)
+ '/' + SUBSTRING(#Date, 5, 4);
SELECT #Date2, CONVERT(DATE, #Date2);
-- 03/25/2014 2014-03-25
EDIT:
Actually, I found a slightly simpler way. I started out with this method but realized that it did not work with ddmmyyyy as opposed to mmddyyyy. I somehow missed that there was an appropriate date style number for dd/mm/yyyy. So, simply adding two slashes to the incoming string and then calling CONVERT does work, but only if you use 103 as the "style". And like the first solution, it requires either changing the incoming parameter to be VARCHAR(10) or CHAR(10) instead of VARCHAR(8), or creating a local variable to be CHAR(10).
DECLARE #Date VARCHAR(8); -- input parameter
SET #Date = '25032014';
DECLARE #Date2 CHAR(10);
SET #Date2 = STUFF(STUFF(#Date, 3, 0, '/'), 6, 0, '/');
SELECT #Date2, CONVERT(DATE, #Date2, 103); -- 103 = dd/mm/yyyy
-- 25/03/2014 2014-03-25
Conversion "styles" can be found on the MSDN page for CAST and CONVERT.
Sorry to be a bother guys. I have been tasked with some code review at a client location and the laptop issued to me does not have SQL installed. While I am waiting for the installation to happen, wanted to get busy looking at the code and came across this gem
CREATE FUNCTION [dbo].[Uf_GetTotalDaysInMonth]
(
-- Add the parameters for the function here
#anydateofMonth datetime
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE #totalDaysInMonth int
-- Add the T-SQL statements to compute the return value here
DECLARE #givendate datetime
SET #givendate = STR(Year(#givendate)) + '-' + STR(Month(#givendate) + 1) + '-01'
select #totalDaysInMonth = datepart(dd, dateadd(day, -1, #givendate))
-- Return the result of the function
RETURN #totalDaysInMonth
END
Ignoring the use of needless extra variable, I believe that this function will crash in December
STR(Month(#givendate) + 1)
will evaluate to 13 and will give an out of scope date error. Could someone please validate this for me?
You vill get error in your function when pass #anydateofMonth December date.
You can use this:
CREATE FUNCTION [dbo].[Uf_GetTotalDaysInMonth]
(
-- Add the parameters for the function here
#anydateofMonth datetime
)
RETURNS int
AS
BEGIN
DECLARE #nextMonth datetime
SET #nextMonth = dateadd(m, 1, #anydateofMonth)
RETURN (SELECT Day(dateadd(d, -Day(#nextMonth), #nextMonth)))
END
http://sqlfiddle.com/#!6/185c9/7
no error on SQL Fiddle, just 13 as output
I have a function which converts all of the strings to datetime.
ALTER FUNCTION formatit(
#fromtime VARCHAR(50) -- varchar
)
RETURNS DATETIME
AS
BEGIN
DECLARE #from datetime
IF (CHARINDEX('NOON',#fromtime,0)) = 0
SET #from = CONVERT(DATETIME, #fromtime)
ELSE
SET #from =CONVERT(DATETIME, '01/01/2000 12pm')
RETURN(#from)
END
SELECT dbo.formatit('04/12/2011 12 ')
So when u see the last select stmt it throws an error saying:
The conversion of a char data type to a datetime data type
resulted in an out-of-range datetime value.
It works fine if i give time 4 pm or 4:00. But it gives an error if i give just 4. Kindly let me know how i can handle this?
You could add a lot of code to look at the string and see if there is a ':' (like you have code to look for NOON). The problem is that if the string ends in 12PM the conversion will work too. So you would have to do something like
ALTER FUNCTION formatit(
#fromtime VARCHAR(50) -- varchar
)
RETURNS DATETIME
AS
BEGIN
DECLARE #from datetime
IF (CHARINDEX('NOON',#fromtime,0)) <> 0
BEGIN
SET #from =CONVERT(DATETIME, '01/01/2000 12pm')
END
ELSE IF (CHARINDEX('PM',#fromtime,0)) = 0 AND (CHARINDEX('AM',#fromtime,0)) = 0 AND (CHARINDEX(':',#fromtime,0)) = 0
BEGIN
SET #fromtime = #fromtime+':00'
SET #from =CAST(#fromtime AS datetime)
END
ELSE
BEGIN
SET #from =CAST(#fromtime AS datetime)
END
return(#from)
END
It looks like whitespace is ignored - I tried these and they all worked...
SELECT dbo.formatit('04/12/2011 12 ')
SELECT dbo.formatit('04/12/2011 12:00')
SELECT dbo.formatit('04/12/2011 12PM')
SELECT dbo.formatit('04/12/2011 12AM')
SELECT dbo.formatit('NOON')
Really you should look at the data you are using to feed this function with something other than TSQL so you have a better string parser.
Your call to dbo.formatit('04/12/2011 12 ') results in a call to convert(datetime, '04/12/2011 12 '). This string is not a valid input to convert to a date/time value.
See the list of formats in the CAST and CONVERT reference in MSDN. If you need to convert this string, you will need to change the time portion into "12:00PM" or just "12:00" (which is assumed to be in the 24-hour format).
First, I would find all the unique time occurrences in your table, something like:
select distinct rtrim(substring(#timeField,charindex(' ',#timeField)+1,99))
as TimePortion
This will give you a sense of what you are dealing with.
Then, in your function, break apart the date and time portions...
Now, based on what you found from the query, you need to spell out what to do with the times you find. For example, if the time portion is numeric, you might simply append :00 to it (i.e. 4 becomes 4:00). If you see NOON, you might replace it with 12:00pm, etc.
ALTER FUNCTION formatit( #fromtime VARCHAR(50) )
RETURNS DATETIME
AS
BEGIN
declare #dtPortion VARCHAR(12)
declare #tmPortion VARCHAR(32)
declare #x INT
SET #x = charindex(' ',#fromTime)
SET #dtPortion = left(#fromTime,#x-1)
SET #tmPortion = rtrim(substring(#fromTime,#x+1,99))
-- Figure out what to do
SELECT #FromTime =
CASE
WHEN IsNumeric(#tmPortion) = 1 THEN #dtPortion+' '+#tmPortion+':00'
WHEN #tmPortion = 'NOON' THEN #dtPortion+' 12:00pm'
ELSE
#dtPortion+' 12:00pm'
END
SET #from =CONVERT(DATETIME, '01/01/2000 12pm')
RETURN(#from)
END
Go
Hope this gets you started