I'm attempting to create a function with 2 params.
1st param is the date
2nd is an int
What i want the function to do:
Function('2014-04-20', 5) results in '2013-11-20'
Function('2013-11-10', 2) results in '2013-09-10'
CREATE FUNCTION MonthDiff(
#in_date DATE
,#in_mn_adjust INT)
RETURNS DATE
AS
BEGIN
DECLARE #in_new DATE;
SET #in_new = DATEADD(MM, -#in_mn_adjust, #in_date);
RETURN #in_new;
END;
I ran 'select dbo.monthdifference('2014-04-22', 3). The error that I got is Conversion failed when converting date and/or time from character string.
What am I doing wrong?
Use below code to solve your problem.
Declare #str Varchar(10)
Declare #result Varchar(10)
set #str= '2012/10/23'
set #result = DATEADD(MONTH,-2,CONVERT(date,#str,102))
Sometimes SQL Server does silly things and misinterprets some date strings1. The following formats are always safe. I believe there are some other formats that are also safe when dealing with the newer date, time and datetime2 types but I tend to play it safe:
YYYYMMDD
YYYY-MM-DD'T'hh:mm:ss
YYYY-MM-DD'T'hh:mm:ss.mil
So try:
select dbo.monthdifference('20140422', 3)
(The 'T' in my example formats is the literal character T, being used as a separator, instead of a space, and instead of the other characters in those format strings which are placeholders, so e.g. 2014-04-24T09:23:00 is in one of my listed safe formats)
1For example, if your language settings are British it interprets nnnn-nn-nn, where all ns are digits, as a YYYY-DD-MM format - despite the fact that I doubt that anyone in Britain would attempt such an interpretation.
Related
In mysql user defined function how to set dynamic return data type based on function execution.
DELIMITER $$
CREATE FUNCTION financeNumberFormat(number double) RETURNS DECIMAL(10,5)
DETERMINISTIC
BEGIN
DECLARE decpoint int(10);
SELECT c_maximum_decimal_values INTO decpoint
FROM mst_xxx
WHERE 1 LIMIT 1;
SET decpoint = FORMAT(number,decpoint);
RETURN (decpoint);
END
My output is coming like below.
financeNumberFormat(5.345)
5.000
The decpoint may vary, so return value should be based on that decimal point. Is there a way to achieve it.? Thanks in advance.
First of all, FORMAT returns a string, since it can contain commas (thousands-separators). So, you may as return VARCHAR(99). By the same token, you may as well feed in strings unless your numbers are really DOUBLE.
Note that going from DECIMAL(m,n) to DOUBLE, then rounding (via FORMAT)d to some number of decimal places is doing 2 roundings, one more than you really need.
Another note: In many situations in MySQL (not all), a string containing numeric data is just as good as DOUBLE or DECIMAL. (The notable exception is with WHERE varchar_col = 1234 will fail to use INDEX(varchar_col).)
I need to convert string for example '0.600 KG' to real. I have tried convert and cast but it generate error message. The example is as bellow.
select cast('0.600 KG' as real)
Error converting data type varchar to real.
Please Help to fix the problem.
Assuming the units always appear at the end of the string, you could try taking an appropriate substring, e.g.
DECLARE #mass VARCHAR(50);
SET #mass = '0.600 KG';
SELECT CAST(SUBSTRING(#mass, 1, CHARINDEX(' ', #mass) - 1) AS real);
Of course, the notion of units would then be lost, and you would just have a real number.
Demo
I have large tables of freely formatted text strings stored in MySQL database. Within each of those strings I have to find three substrings which are specifically formatted. This problem looks like an ideal fit for MySQL REGEXP pattern matching.
I know that MySQl REGEXP operator returns only True or False. Moreover, because I need to process large tables, I would need to achieve the goal within MySQL and not to involve PHP or any other server side language.
Example of source data:
FirstEntry_somestring_202320047A_210991957_700443250_Lieferadresse:_modified string c/o Logistics, some address and another text
SecondEntry_hereisanothertext_210991957_text_202320047A_and_700443250_another text which does not have any predefined structure
ThirdEntry_700443250_210991957_202320047A_Lieferadresse:_here some address, Logistics, and some another text with address.
FourthEntry some very long text before numbers__202320047A-700443250-210991957-Lieferadresse:, another text with address and company name. None of this text has predefined structure
The examples above have are four strings stored as TEXT datatypes within MySQL table. They do not have any specific structure. I know however, that somewhere in each records must be three numbers freely delimited and but they have specific format:
Regex Format: '\d{3}(30|31|32)\d{4}[A-Z])'
Regex Format:'(\d{3}(99)\d{4})')
Regex Format: '((700)\d{6})'
Could you please help me how can I get the substrings matching the Regex patterns in the text above?
The Server runs on:
Windows OS
IIS 7
MySQL for Windows
PHP
...
Thank you!
MariaDB 10.0.5 (from 2013) is virtually the same as MySQL, but it includes the full set of REGEXP. Also it has REGEXP_REPLACE().
See https://mariadb.com/kb/en/mariadb/pcre/
For those interested in this question, I have developed my own solution using MySQL Stored Procedures.
I think, this is the most valuable solution on this subject on StackOverflow, as it provides real solution. In contrast to others, there were only vague ideas offered:
-- Return REGEX Value
DELIMITER $$
DROP PROCEDURE IF EXISTS RETURNREGEX$$
CREATE PROCEDURE RETURNREGEX(IN strSentence VARCHAR(1024), IN regex_str VARCHAR(1024), IN length_str INT )
BEGIN
DECLARE index_str INT DEFAULT 0;
DECLARE match_str VARCHAR(1024) DEFAULT '';
DECLARE result BOOL DEFAULT FALSE;
REPEAT
-- Get substring with predefined length
SELECT SUBSTRING(strSentence, index_str, length_str) INTO match_str;
-- compare this substring agains REGEX to see if we have match
SELECT match_str REGEXP regex_str INTO result;
SET index_str = index_str + 1;
-- evaluate result (TRUE / FALSE)
UNTIL result OR index_str > length(strSentence)
END REPEAT;
IF result = TRUE THEN SELECT match_str;
ELSE SELECT NULL;
END IF;
END$$
DELIMITER ;
Using SQL-Server 2008 and concatenating string literals to more than 8000 characters by obvious modification of the following script, I always get the result 8000. Is there a way to tag string literals as varchar(max)?
DECLARE #t TABLE (test varchar(max));
INSERT INTO #t VALUES ( '0123456789012345678901234567890123456789'
+ '0123456789012345678901234567890123456789'
+ '... and 200 times the previous line'
);
select datalength(test) from #t
I used the following code on SQL Server 2008
CREATE TABLE [dbo].[Table_1](
[first] [int] IDENTITY(1,1) NOT NULL,
[third] [varchar](max) NOT NULL
) ON [PRIMARY]
END
GO
declare #maxVarchar varchar(max)
set #maxVarchar = (REPLICATE('x', 7199))
set #maxVarchar = #maxVarchar+(REPLICATE('x', 7199))
select LEN(#maxVarchar)
insert table_1( third)
values (#maxVarchar)
select LEN(third), SUBSTRING (REVERSE(third),1,1) from table_1
The value you are inserting in your example is being stored temporally as a varchar(8000) because. To make the insert one will need to use a variable which is varchar(max) and append to it to overcome the internal 8000 limit.
Try casting your value being inserted as a varchar(max):
INSERT INTO #t VALUES (CAST('0123456789012345678901234567890123456789'
+ '0123456789012345678901234567890123456789'
+ '... and 200 times the previous line' AS varchar(max)
);
Also, you may have to concatenate several <8000 length strings (each casted as varchar(max)).
See this MSDN Forum Post.
When I posted the question, I was convinced that there are some limitations for the length or maximal line width of a single string literal to be used in INSERT and UPDATE statement.
This assumption is wrong.
I was led to this impression by the fact the SSMS limits output width for a single column in text mode to 8192 characters and output of PRINT statements to 8000 characters.
Fact is, as far as I know you need only enclose the string with apostrophes and double all embedded apostrophes. I found no restrictions concerning width or total length of a string.
For the opposite task, to convert such strings back from database back to script the best tool I found is ssms toolspack which works for SQL-Server 2005+.
I have a field type varchar in sql server. It contains data like "010109" etc.
When I try to convert this to DATETIME it returns a value "9 Jan 2001" when the actual value should be "1 Jan 2009".
Does anybody have a fix for this?
Thanks for your help.
I thought there would be some conversion format so you could put:
select(convert(datetime,'010109',<some magic number>))
and get the result, but I can't seem to find one that gives the right date :(
This works, but is pretty nasty:
declare #dt varchar(6)
select #dt = '010109'
select convert(datetime,RIGHT(#dt,2) + SUBSTRING(#dt,3,2) + LEFT(#dt,2))
Yeesh
When you type date in the format of 'xxxxxx' it seems that SQLServer assumess it is an ISO format yymmdd and as such it is not affected by the SET DATEFORMAT
I was aware of 2 such formats - so called safe formats
ISO: yyyymmdd
ISO8601:yyyy-mm-ddThh:mi:ss.mmm
but it seems that yymmdd is also ISO - check BOL Date and Time Styles - format 12
That would explain why the solution posted by Scorpio did not work
You can use the solution provided by butterchicken with the format specification (12) to be on a safe side:
declare #dt varchar(6)
select #dt = '010109'
select convert(datetime,RIGHT(#dt,2) + SUBSTRING(#dt,3,2) + LEFT(#dt,2),12)
If possible I would be ideal if you could change the column to datetime to avoids similar surprises in the future
SQL Server is expecting the date to be in the format YMD
So if your string was like this '090101' you would get the proper date.
select(convert(datetime,'090101',104))
So you will have to substring out the parts and run the convert.