Truncated Inccorrect date value while calling nested function - mysql

I have two function.
fn_validate_date
fn_validation
fn_validate_date code:
CREATE DEFINER=`root`#`localhost` FUNCTION `fn_validate_date`(
`dt_date` DATE
)
RETURNS date
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Returns the associated value of given attribute for given employee for a particular date.'
BEGIN
SET dt_date = IF(dt_date IS NULL OR dt_date ='', CURRENT_DATE, dt_date);
RETURN dt_date;
END
fn_validation code:
CREATE DEFINER=`root`#`localhost` FUNCTION `fn_validation`(
`dt_date` DATE
)
RETURNS date
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
RETURN fn_validate_date(dt_date);
END
Now when I am calling fn_validate_date as below
SELECT `fn_validate_date`(null);
It's working well but when I calling fn_validation it's giving me an error.
SELECT `fn_validation`(null);
My question is why I didn't get error while calling fn_validate_date?

In fn_validate_date, the dt_date-parameter is type of date and you are comparing it to a string datatype. No need for that. Date datatype cannot contain ''. It either is NULL or has a date value in it.
So instead of:
SET dt_date = IF(dt_date IS NULL OR dt_date ='', CURRENT_DATE, dt_date);
You can simply use:
return ifnull( dt_date, current_date() );

I disable strict mode and it's working well.
SET sql_mode =''
To disable strict mode in MySQL. I am not sure why MySql short-circuited IF condition as I am passing NULL in the input parameter of fn_validation.

Related

I Getting error when run this below query : RETURN statements in scalar valued functions must include an argument

I am getting this error message
RETURN statements in scalar valued functions must include an argument
when run this query:
create function gender(#gender nvarchar(40))
returns nvarchar(40)
as
begin
(select name,cast(DOB as date) as DOB from datenames where gender = #gender)
return
end
The write way to create a function in mysql for your example is as follows:
DELIMITER \\
create function gender(Igender nvarchar(40))
returns nvarchar(40)
begin
DECLARE customerLevel NVARCHAR(40);
IF EXISTS (select name,cast(DOB as date) as DOB from datenames where gender = Igender) THEN
SET customerLevel = 'SOMETHING1';
ELSE
SET customerLevel = 'SOMETHING2';
END IF;
RETURN (customerLevel);
end
No need to as
No need to # before input
You need to return something.
Don't forget to use DELIMITER.
If you use phpmyadmin and has problem with nvarchar read this post: Unrecognize data type nvarchar in database or simply change it to to varchar.

what if data is changed in database, what does deterministic keyword do?

So I have this stored function added in mysql workbench:
CREATE FUNCTION `getfullAdd` (id INT unsigned)
RETURNS VARCHAR(160)
CHARACTER SET utf8
COMMENT 'function that returns all addresses with character string when you enter customer number'
DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE addfound VARCHAR(160) CHARACTER SET utf8;
SELECT CONCAT_WS(', ', addr01, addr02) INTO addfound FROM dtb_customer WHERE customer_id=id;
RETURN addfound;
END
I'm bit new to this DETERMINISTIC keyword.
What does it do to the function above?
If set by this keyword, does function return the same value by the same parameter?
If customer's address is changed, does this function returns different result from the same parameter?
From the manual
"A routine is considered “deterministic” if it always produces the same result for the same input parameters, and “not deterministic” otherwise. "
https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
So your function is DETERMINISTIC as long as none of the customer id's change.

How to validate input date in YYYY-MM-DD format inside the MySQL procedure

I have one DATE input parameter for a procedure ex: IN p_date DATE.I want to validate this input DATE parameter format inside a procedure which should be in YYYY-MM-DD format. If the input parameter is having characters or date format is wrong it should through an exception using SIGNAL.
Please find the below code what i written
CREATE PROCEDURE `validation_check`(IN pdate_time DATE)
BEGIN
DECLARE InputValidation CONDITION FOR SQLSTATE '45000';
DECLARE dateValidation CONDITION FOR SQLSTATE '45000';
/* Doing NULL validation */
IF pdate_time IS NULL THEN
SIGNAL InputValidation
SET MESSAGE_TEXT='pdate_time should not be empty.';
END IF;
/* Doing Date format validation
IF STR_TO_DATE(pdate_time,'%Y-%m-%d') != pdate_time THEN
SIGNAL dateValidation
SET MESSAGE_TEXT='Input Date format should be in YYYY-MM-DD.';
END IF;
*/
/* Doing Date format validation */
IF pdate_time NOT REGEXP '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/' THEN
SIGNAL dateValidation
SET MESSAGE_TEXT='Input Date format should be in YYYY-MM-DD.';
END IF;
SELECT pdate_time;
END
Thanks,
Sagar
TL;DR
Regular expression will fail in this case, because they may only check date format, but not if it is a valid date (as, for example, '2014-02-30' has correct format but invalid data for date)
Use string functions
Concept
The solution is - yes, use string functions. However, regular expressions will also be useful - to check if format was good, you still need to check date itself. Since validation of date is a single separated issue - you should create a function for it. That function will accept string and return result as boolean value - so either date is ok or not. This will be re-usable and, therefore, more flexible.
Code
Here we go with the function:
CREATE FUNCTION VALIDATE_DATE(d VARCHAR(255))
RETURNS INT
BEGIN
DECLARE date_year VARCHAR(255) DEFAULT '';
DECLARE date_month VARCHAR(255) DEFAULT '';
DECLARE date_day VARCHAR(255) DEFAULT '';
DECLARE ym_delim INT DEFAULT 0;
DECLARE md_delim INT DEFAULT 0;
-- First, if it's just not xxx-yyy-zzz format:
SET ym_delim = LOCATE('-', d);
SET md_delim = LOCATE('-', d, ym_delim+1);
IF !ym_delim || !md_delim THEN
RETURN FALSE;
END IF;
-- Second, if resulted members are not YYYY, MM or DD:
SET date_year = SUBSTR(d, 1, ym_delim-1);
SET date_month = SUBSTR(d, ym_delim+1, md_delim-ym_delim-1);
SET date_day = SUBSTR(d, md_delim+1);
IF date_year NOT REGEXP '^[0-9]{4}$'
|| date_month NOT REGEXP '^[0-9]{2}$'
|| date_day NOT REGEXP '^[0-9]{2}$' THEN
RETURN FALSE;
END IF;
-- Finally, check if date itself is ok, like 2014-02-30 isn't ok:
IF DATE(CONCAT(date_year, '-', date_month, '-', date_day)) IS NULL THEN
RETURN FALSE;
END IF;
RETURN TRUE;
END//
DELIMITER ;
As you can see, we have three cases, when date validating fails:
First, if there are no proper delimiters (which are -). Then year, month and day just can't be found
Second, if extracted year, month and day part are just bad (for instance, date was foo-bar-baz). That's why we can't use date functions to extract those parts and so we have to use string functions.
Third - finally, if our date parts seems to be good, there still may be false result because of invalid combination (2014-13-01 has wrong month, for example).
Seems to be a solution
There is, however, STR_TO_DATE() function which may look like solution. Unfortunately, it will pass date parts which are not in corresponding format (such as 2014-1-1) - thus, it can't be used for direct format validation. That is why I used separate stored function instead.
What will be passed
All YYYY-MM-DD dates, which are correct in terms of MySQL, will be passed. That is, early dates, such as '0001-01-01' are correct :
mysql> SELECT VALIDATE_DATE('0001-01-01');
+-----------------------------+
| VALIDATE_DATE('0001-01-01') |
+-----------------------------+
| 1 |
+-----------------------------+
1 row in set (0.00 sec)
And, in fact, they should be correct, because they are valid for MySQL. However, such things as 001-01-01 won't be passed even despite fact, that such strings are correct for MySQL dates too:
mysql> SELECT VALIDATE_DATE('001-01-01'), DATE('001-01-01');
+----------------------------+-------------------+
| VALIDATE_DATE('001-01-01') | DATE('001-01-01') |
+----------------------------+-------------------+
| 0 | 0001-01-01 |
+----------------------------+-------------------+
1 row in set (0.00 sec)
And that is derived from your format expectations - you should filter all the things, which do not have YYYY-MM-DD format exactly, thus, you'll have such results.

Simple T-SQL function to convert date to displayable format

I have a strange bug that I cannot resolve (with a one line function).
This code works:
DECLARE #TestDate datetime = '2013-05-01 23:15:11'
select IsNull(convert(varchar(max), #TestDate, 120), 'null') as 'test1'
Displays: 2013-05-01 23:15:11
CREATE FUNCTION [dbo].[DateOrNullToChar] (#InputDate date)
RETURNS VARCHAR(40)
BEGIN
return ISNULL(convert(varchar(40),#InputDate, 120),'null');
END
select dbo.DateOrNullToChar('2013-05-01 23:15:11') as 'result'
Returns: 2013-05-01 (no time)
I have also tried varchar(max).
The purpose of the function is for something like this:
Set #ErrorMessage = ' #ArrivalDate=' + dbo.DateOrNullToChar(#ArrivalDate) +
' #DepartureDate=' + dbo.DateOrNullToChar(#DepartureDate);
If any one value is null, the whole value becomes null. So I want to see the string 'null' when a date has a null value.
#InputDate should be datetime or datetime2 if you want time to be shown
The clues are in the code...
#TestDate datetime
#InputDate date
You need to make the parameter type to be datetime instead of date:
CREATE FUNCTION [dbo].[DateOrNullToChar] (#InputDate datetime)
It's silently converting the string to your date parameter type and thus dropping the time portion.

Optional parameters in SQL Server stored procedure

I'm writing some stored procedures in SQL Server 2008. Is the concept of optional input parameters possible here?
I suppose I could always pass in NULL for parameters I don't want to use, check the value in the stored procedure, and then take things from there, but I was interested if the concept is available here.
You can declare it like this:
CREATE PROCEDURE MyProcName
#Parameter1 INT = 1,
#Parameter2 VARCHAR (100) = 'StringValue',
#Parameter3 VARCHAR (100) = NULL
AS
/* Check for the NULL / default value (indicating nothing was passed) */
if (#Parameter3 IS NULL)
BEGIN
/* Whatever code you desire for a missing parameter */
INSERT INTO ........
END
/* And use it in the query as so */
SELECT *
FROM Table
WHERE Column = #Parameter
Yes, it is. Declare the parameter as so:
#Sort varchar(50) = NULL
Now you don't even have to pass the parameter in. It will default to NULL (or whatever you choose to default to).
In SQL Server 2014 and above at least, you can set a default, and it will take that and not error when you do not pass that parameter.
Partial example: the third parameter is added as optional. Execution (exec) of the actual procedure with only the first two parameters worked fine.
exec getlist 47,1,0
create procedure getlist
#convId int,
#SortOrder int,
#contestantsOnly bit = 0
as
The default mentioned in previous answers only works for simple cases. In more complicated cases, I use an IF clause near the beginning of the stored procedure to provide a value, if the parameter is NULL or empty and calculations are required.
I often use optional parameters in the WHERE clause, and discovered that SQL does not short circuit logic, so use a CASE statement to make sure not to try to evaluate NULL or empty dates or unique identifiers, like so:
CREATE Procedure ActivityReport
(
#FromDate varchar(50) = NULL,
#ToDate varchar(50) = NULL
)
AS
SET ARITHABORT ON
IF #ToDate IS NULL OR #ToDate = '' BEGIN
SET #ToDate = CONVERT(varchar, GETDATE(), 101)
END
SELECT ActivityDate, Details
FROM Activity
WHERE
1 = CASE
WHEN #FromDate IS NULL THEN 1
WHEN #FromDate = '' THEN 1
WHEN ActivityDate >= #FromDate AND ActivityDate < DATEADD(DD,1,#ToDate) THEN 1
ELSE 0
END