DB2: How to validate date in String format which is a varchar data type - sql

I need to know wheather a data in a column of type varchar is in correct date format or not .
I have to do the same in DB2.
I have done this in java by using SimpleDateFormat() and Date.Parse() functions with the help of Exception handling .
I'm posting my java code to validate a string to date
private boolean isValidDate(String date) {
try{
DateFormat d = new SimpleDateFormat("yyyyMMdd");
d.setLenient(false);
d.parse(date);
return true;
}
catch(Exception e){
return false;
}
}
but now i have to do the same in DB2 data base.Can i use any functions or procederes in DB2
my data in table column is like this..
20140231
20000101
.
.
.
yyyyMMdd
and column type is varchar

My style of display the date:
try
{
Date dob = new SimpleDateFormat("yyyy-MMM-dd").parse(request.getParameter("date"));
user.setDate(date);
}
catch(ParseException e)
{
e.printStackTrace();
}
note: if you should give like as yyyy-MMM-dd or MM/dd/yyyy
your programs as:
private boolean isValidDate(String date)
{
try
{
DateFormat d = new SimpleDateFormat("MMM/dd/yyyy").parse(request.getParameter("date"));
d.setLenient(false);
d.parse(date);
return true;
}
catch(Exception e)
{
return false;
}
}
Timestamp to varchar:
timestamp-expression
An expression that returns a value that must be a DATE or TIMESTAMP, or a valid string representation of a date or timestamp that is not a CLOB or DBCLOB.
If the argument is a string, the format-string argument must also be specified.
In a Unicode database, if a supplied argument is a graphic string representation of a data, time, or timestamp, it is first converted to a character string before evaluating the function.
If timestamp-expression is a DATE or a valid string representation of a date, it is first converted to a TIMESTAMP(0) value, assuming a time of exactly midnight (00.00.00).
For the valid formats of string representations of datetime values, see "String representations of datetime values" in "Datetime values".
format-string
The expression must return a value that is a built-in CHAR, VARCHAR, numeric, or datetime data type.
If the value is not a CHAR or VARCHAR data type, it is implicitly cast to VARCHAR before evaluating the function.
In a Unicode database, if the supplied argument is a GRAPHIC or VARGRAPHIC data type, it is first converted to VARCHAR before evaluating the function. The actual length must not be greater than 254 bytes (SQLSTATE 22007).
The value is a template for how timestamp-expression is to be formatted.
A valid format-string must contain a combination of the format elements listed below (SQLSTATE 22007).
Two format elements can optionally be separated by one or more of the following separator characters:
minus sign (-)
period (.)
slash (/)
comma (,)
apostrophe (')
semi-colon (;)
colon (:)
blank ( )
note:
click 1
click2
UPDATE:
sample code 1: Convert the current date to YYYYMM format
SELECT DATE_FORMAT(NOW(), '%Y%m');
o/p: # 201403
sample code 2: Convert the current date to YYYYMM format
SELECT VARCHAR_FORMAT(CURRENT_DATE, 'YYYYMM') FROM jmail;
o/p # 201403
sample:
No | MySQL | DB2 |SampleOutput
1 | DATE_FORMAT(NOW(), '%Y-%m-%d) | VARCHAR_FORMAT(CURRENT_DATE,'YYYY-MM-DD')| 2013-02-14
2 | DATE_FORMAT(NOW(), '%d/%m/%y')| VARCHAR_FORMAT(CURRENT_DATE,'DD/MM/RR') | 14/02/13

It's not clear what "flavor" of DB2 is needed. With DB2 for i, I'd probably create a function to do the test and return an indication of success or failure. Here's an example that works for me:
DROP SPECIFIC FUNCTION SQLEXAMPLE.CHKVCDATE ;
SET PATH "QSYS","QSYS2","SYSPROC","SYSIBMADM","SQLEXAMPLE" ;
CREATE FUNCTION SQLEXAMPLE.CHKVCDATE (
VCDATE VARCHAR(20) )
RETURNS INTEGER
LANGUAGE SQL
SPECIFIC SQLEXAMPLE.CHKVCDATE
DETERMINISTIC
CONTAINS SQL
RETURNS NULL ON NULL INPUT
NO EXTERNAL ACTION
NOT FENCED
SET OPTION ALWBLK = *ALLREAD ,
ALWCPYDTA = *OPTIMIZE ,
COMMIT = *CHG ,
CLOSQLCSR = *ENDMOD ,
DECRESULT = (31, 31, 00) ,
DFTRDBCOL = *NONE ,
DYNDFTCOL = *NO ,
DYNUSRPRF = *USER ,
SRTSEQ = *HEX
BEGIN ATOMIC
DECLARE CHKDATE DATE ;
DECLARE VALIDDATE INT ;
DECLARE NOT_VALID CONDITION FOR '22007' ;
DECLARE CONTINUE HANDLER FOR NOT_VALID
SET VALIDDATE = -1 ;
SET VALIDDATE = 0 ;
VALUES ( VCDATE ) INTO CHKDATE ;
RETURN VALIDDATE ;
END ;
COMMENT ON SPECIFIC FUNCTION SQLEXAMPLE.CHKVCDATE
IS 'Check VARCHAR for valid date' ;
Any properties or other details that don't fit your particular DB2 can be removed or changed. The size of the VCDATE VARCHAR parm might need adjustment, and the RETURN value can be whatever you need. The function might be useful in a WHERE clause.
I can invoke it like this:
select sqlexample.chkvcdate('2014-02-29'), sqlexample.chkvcdate('2014-02-28') from sysibm.sysdummy1
The first will return ( -1 ) for the invalid value, and the second will return ( 0 ) for valid.

Related

Conversion failed when converting the nvarchar value to data type int sql server

I have a table. There is data in this table and there is a checkbox next to each data. Multiple selection is possible. After the user makes a selection, the id numbers of the selected columns are come in the array. I convert the array to string and send it to the stored procedure and I run the following stored procedure:
Example value for #ResultsIds: 65, 66, 67, 68, 125
#ResultsIds nvarchar(250)
UPDATE MyTable SET [IsVerified] = 1 WHERE Id IN (#ResultsIds)
And I got this error:
Conversion failed when converting the nvarchar value '65, 66, 67, 68, 125' to data type int. Because [Id] column is int data type.
I tried CAST and CONVERT functions of SQL but it didn't work.
SQL Server doesn't do that automatically. Assuming you're on a recent version, you can do this:
declare #ResultsIds nvarchar(250) = '65,66,67,68,125'
UPDATE MyTable
SET [IsVerified] = 1
WHERE Id IN (
select [value]
from string_split(#ResultIDs, ',')
)
declare #ResultsIds nvarchar(250)='65,66,67,68,125'
UPDATE MyTable SET [IsVerified] = 1 WHERE cast(Id as varchar) IN (#ResultsIds)
I solved problem using foreach. I separated the numbers in the string from commas and transferred each number to the array. Then I updated the array one by one by running foreach loop.
public void Verify(DB db, string rows)
{
int[] nums = Array.ConvertAll(rows.Split(','), int.Parse);
foreach (int value in nums)
{
DbCommand cmd = db.GetStoredProcCommand("VerifyProcess");
db.AddInParameter(cmd, "#ResultId", DbType.Int32, value);
db.ExecuteNonQuery(cmd);
}
}

Passing char value to function

I have the following function:
CREATE OR REPLACE FUNCTION BANINST1."F_COC_AUTO_AWARD_FILTER" (pidm number) return number
as
return_field number;
cursor get_pidm is
select distinct SHRDGMR.SHRDGMR_PIDM
from SATURN.SHRDGMR SHRDGMR,
SATURN.SORLCUR SORLCUR,
SATURN.SORLFOS SORLFOS,
DWSCHEMA.DAP_AUDIT_DTL#LINKDWTEST
where SORLCUR.SORLCUR_PIDM = SHRDGMR.SHRDGMR_PIDM
and SORLFOS.SORLFOS_PIDM = SORLCUR.SORLCUR_PIDM
and SORLCUR.SORLCUR_LEVL_CODE = SHRDGMR.SHRDGMR_LEVL_CODE
and SORLCUR.SORLCUR_DEGC_CODE = SHRDGMR.SHRDGMR_DEGC_CODE
and SORLFOS.SORLFOS_TERM_CODE = SORLCUR.SORLCUR_TERM_CODE
and SHRDGMR.SHRDGMR_PIDM = pidm
and SHRDGMR.SHRDGMR_DEGS_CODE = 'AW'
and SORLCUR.SORLCUR_PROGRAM in ('STCC', 'CC')
and DWSCHEMA.DAP_AUDIT_DTL.DAP_DEGREE in ('CPCC-CDS', 'CC1-CDS', 'CC2-CDS')
and SORLFOS.SORLFOS_MAJR_CODE <> DWSCHEMA.DAP_AUDIT_DTL.DAP_AUD_VALUE2
and trim(DWSCHEMA.DAP_AUDIT_DTL.DAP_STU_ID) = (select spriden_id from spriden where spriden_pidm = pidm and spriden_change_ind is null);
begin
open get_pidm;
fetch get_pidm into return_field;
close get_pidm;
return return_field;
end;
/
This is the call to the function from a where clause:
baninst1.f_coc_auto_award_filter#test(RAD_PRIMARY_MST.RAD_USER_DEF1) is not null
The function accepts a number data type parameter.
The passed column RAD_PRIMARY_MST.RAD_USER_DEF1 is a char(12) data type that has a value such as 293858.
The following error is returned when calling the function: ORA-01722: invalid number
I have tried to pass a number value to the function in several different ways:
baninst1.f_coc_auto_award_filter#test(to_number(trim(RAD_PRIMARY_MST.RAD_USER_DEF1))) is not null
baninst1.f_coc_auto_award_filter#test(cast(RAD_PRIMARY_MST.RAD_USER_DEF1 as number(8))) is not null
All attempts return the same error ORA-01722: invalid number
If I hard-code the D_PRIMARY_MST.RAD_USER_DEF1 value to a number, the function call works.
baninst1.f_coc_auto_award_filter#test(293858) is not null
How do I pass the char value from RAD_PRIMARY_MST.RAD_USER_DEF1 to the function?
This might be the keyword:
such as 293858
Are you sure that there aren't any non-numeric values in that column? With that datatype (char), there's always doubt. If you are storing numbers in there, why isn't it number?
This query should return invalid values which cause your code to break.
select * from d_primary_mst where not regexp_like(rad_user_def1, '^\d+$')
Also, if you are passing a string, why do you force the function to accept a number? Why don't you
CREATE OR REPLACE FUNCTION BANINST1.F_COC_AUTO_AWARD_FILTER
(pidm RAD_PRIMARY_MST.RAD_USER_DEF1%type)
return SHRDGMR.SHRDGMR_PIDM%type
as
return_field SHRDGMR.SHRDGMR_PIDM%type;
cursor get_pidm is
select distinct SHRDGMR.SHRDGMR_PIDM ...
By the way, get rid of double quotes when creating Oracle objects; they only cause problems.

DB2 select ... insert fails converting a leap day into a date

I am attempting to do a select insert which takes a DECIMAL(8,0) representation of a date (DOB), converts it into a date, and inserts it into another table.
INSERT INTO myschema.beneficiary_info
(name, address, city, state, zip, dob, spouse)
SELECT
jh.bname, jh.badd1, jh.bcity, jh.bstate, jh.bzip,
CASE
WHEN JH.BDOB8 != '0' AND JH.BDOB8 IS NOT NULL THEN
DATE(
TIMESTAMP_FORMAT(
CHAR(jh.bdob8) ,'YYYYMMDD'))
ELSE null
END,
--jh.bdob8,
jh.bspous
FROM TABLE(MYSCHEMA.REMOTE_TABLE()) JH -- function pointing to a remote database
But, about 5,000 records into it (having successfully processed dates and nulls), it fails with
[Code: -181, SQL State: 22007] [SQL0181] Value in date, time, or timestamp string not valid.
I narrowed the data down to the offending row, and found this (showing results of case statement and the actual bdob8 field:
0006 bdob8
1958-12-24 19581224
(null) 19620229
1965-02-07 19650207
The leap day appears to be causing the select ... insert to fail.
At this point, the case statement has already successfully navigated nulls by simply passing the null to the insert. Yet for some reason, when the date/timestamp functions barf and return a null, the whole thing breaks.
Looking for ideas how to overcome the apparent inability to handle leap days...
(Using IBMi DB2 V7R3M0 L00)
As Gordon pointed out, 1962 isn't a leap year.
I'd suggest building your own User Defined Function (UDF) that does the date conversions...
That way you'll be in control of what's returned for invalid dates. You can also handle common numeric special values (or return null)
exmaple
00000000 --> 0001-01-01
99999999 --> 9999-12-31
There's a popular open source package of UDF's available, iDate by Alan Campin, that would make a great starting place for your own UDF.
Use a UDF to filter bad data
CREATE FUNCTION ASDATE (
INPUTDATESTR VARCHAR(10) )
RETURNS DATE
LANGUAGE SQL
SPECIFIC ASDATE
NOT DETERMINISTIC
MODIFIES SQL DATA
CALLED ON NULL INPUT
CONCURRENT ACCESS RESOLUTION DEFAULT
SET OPTION ALWBLK = *ALLREAD ,
ALWCPYDTA = *OPTIMIZE ,
COMMIT = *NONE ,
DECRESULT = (31, 31, 00) ,
DYNDFTCOL = *NO ,
DYNUSRPRF = *USER ,
SRTSEQ = *HEX
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN NULL ;
RETURN DATE ( TIMESTAMP_FORMAT ( CHAR ( INPUTDATESTR ) , 'YYYYMMDD' ) ) ;
END ;
It is accessed like this:
INSERT INTO myschema.beneficiary_info
(name, address, city, state, zip, dob, spouse)
SELECT
jh.bname, jh.badd1, jh.bcity, jh.bstate, jh.bzip,
CASE WHEN ASDATE(jh.bdob8) IS NOT NULL THEN ASDATE(jh.bdob8) ELSE NULL END
--jh.bdob8,
jh.bspous
FROM TABLE(MYSCHEMA.REMOTE_TABLE()) JH -- function pointing to a remote database
Many thanks to Charles' pointing me in the right direction, and https://stackoverflow.com/a/39683452/2129574
The options in the UDF are the defaults that IBM Navigator for i filled in; any comments about improvements to the function are welcomed.

Error creating function in DB2 with params

I have a problem with a function in db2
The function finds a record, and returns a number according to whether the first and second recorded by a user
The query within the function is this
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = '0010111003')
) AS T WHERE POLLIFE = '0010111003'
And works perfect
I create the function with this code
CREATE FUNCTION LIBWEB.BNOWPAPOL(POL CHAR)
RETURNS DECIMAL(7,2)
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
RETURN (
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = POL)
) AS T WHERE POLLIFE = POL
)
The command runs executed properly
WARNING: 17:55:40 [CREATE - 0 row(s), 0.439 secs] Command processed.
No rows were affected
When I want execute the query a get a error
SELECT LIBWEB.BNOWPAPOL('0010111003') FROM DATAS.DUMMY -- dummy has only one row
I get
[Error Code: -204, SQL State: 42704] [SQL0204] BNOWPAPOL in LIBWEB
type *N not found.
I detect, when I remove the parameter the function works fine!
With this code
CREATE FUNCTION LIBWEB.BNOWPAPOL()
RETURNS DECIMAL(7,2)
LANGUAGE SQL
NOT DETERMINISTIC
READS SQL DATA
RETURN (
SELECT
CASE
WHEN NUM IN (1,2) THEN 5
ELSE 2.58
END AS VAL
FROM (
select ROW_NUMBER() OVER() AS NUM ,s.POLLIFE
from LQD943DTA.CAQRTRML8 c
INNER JOIN LSMODXTA.SCSRET s ON c.MCCNTR = s.POLLIFE
WHERE s.NOEMP = ( SELECT NOEMP FROM LSMODDTA.LOLLM04 WHERE POLLIFE = '0010111003')
) AS T WHERE POLLIFE = '0010111003'
)
Why??
This statement:
SELECT LIBWEB.BNOWPAPOL('0010111003') FROM DATAS.DUMMY
causes this error:
[Error Code: -204, SQL State: 42704] [SQL0204] BNOWPAPOL in LIBWEB
type *N not found.
The parm value passed into the BNOWPAPOL() function is supplied as a quoted string with no definition (no CAST). The SELECT statement assumes that it's a VARCHAR value since different length strings might be given at any time and passes it to the server as a VARCHAR.
The original function definition says:
CREATE FUNCTION LIBWEB.BNOWPAPOL(POL CHAR)
The function signature is generated for a single-byte CHAR. (Function definitions can be overloaded to handle different inputs, and signatures are used to differentiate between function versions.)
Since a VARCHAR was passed from the client and only a CHAR function version was found by the server, the returned error fits. Changing the function definition or CASTing to a matching type can solve this kind of problem. (Note that a CHAR(1) parm could only correctly handle a single-character input if a value is CAST.)

String operation in SQL to reverse a string

In DB2 9.7 I am looking for a way to reverse a string in a SQL query.
I am familiar with SQL Server where the query would be like
SELECT
REVERSE(LEFT_TO_REIGHT) AS RIGHT_TO_LEFT
FROM
TABLE1;
I couldn't find a similar function in DB2. is there a simple way to reverse a string?
Creating a REVERSE(..) function is unnecessary.
DB2 has something called RIGHT(string-expression, length):
The RIGHT function returns the rightmost string of string-expression
of length length, expressed in the specified string unit. If
string-expression is a character string, the result is a character
string. If string-expression is a graphic string, the result is a
graphic string
So if you're interested in the last 8 characters, you can pretty trivially do this via:
SELECT RIGHT(left_to_right, 8) AS right_to_left
FROM Table1
(I'm actually still concerned about the fact that you're splitting off 8 characters consistently, as it implies you have a multi-part key of some sort).
Try something like:
SELECT STRIP(CAST( TRANSLATE('87654321',LEFT_TO_REIGHT, '12345678') AS VARCHAR(8) ))
FROM TABLE1;
Due to the original question this is the first webpage that comes up when one searches for 'How to reverse a string in DB2'.
Here is an answer that doesn't require implementing it in C and shouldn't brake on non-pure-Engilsh strings regardless of their length.
Be warned though, the efficiency is 'meh' at best.
CREATE FUNCTION REVERSE_STRING(STR VARCHAR(100))
RETURNS VARCHAR(100)
LANGUAGE SQL
SPECIFIC REVERSE_STRING
DETERMINISTIC
REVERSE: BEGIN
DECLARE REVERSED_STRING VARCHAR(100);
DECLARE REVERSED_CHARACTERS_INDEX INTEGER;
SET REVERSED_STRING='';
SET REVERSED_CHARACTERS_INDEX=0;
WHILE (REVERSED_CHARACTERS_INDEX < CHARACTER_LENGTH(STR, CODEUNITS16))
DO
SET REVERSED_CHARACTERS_INDEX = REVERSED_CHARACTERS_INDEX + 1;
SET REVERSED_STRING = CONCAT(
REVERSED_STRING,
LEFT(RIGHT(STR, REVERSED_CHARACTERS_INDEX, CODEUNITS16), 1, CODEUNITS16));
END WHILE;
RETURN REVERSED_STRING;
END REVERSE#
The idea is to get a substring which starts from the n-th character from the right till the end of the string, then take the first element of this substring from the left and append it to a reversed string. This operation is conducted n times where n is the length of a string to be reversed.
You can use it like any other function.
SELECT FIRSTNME AS FIRSTNAME, REVERSE_STRING(FIRSTNME) AS REVERSED_FIRSTNAME
FROM SAMPLE.EMPLOYEE#
Example output
Answering the original question of reversing a string there's user defined functions published on the IBM site that will do it that you can find here. There's apparently no built in ability in DB2
https://www.ibm.com/developerworks/community/blogs/SQLTips4DB2LUW/entry/reverse?lang=en
Tortured SQL version:
CREATE OR REPLACE FUNCTION REVERSE(INSTR VARCHAR(4000))
RETURNS VARCHAR(4000) SPECIFIC REVERSE
DETERMINISTIC NO EXTERNAL ACTION CONTAINS SQL
RETURN WITH rec(pos, res) AS (VALUES (1, CAST('' AS VARCHAR(4000)))
UNION ALL
SELECT pos + 1, SUBSTR(INSTR, pos , 1) || res
FROM rec
WHERE pos <= LENGTH(INSTR)
AND pos < 5000)
SELECT res FROM rec WHERE pos > LENGTH(INSTR);
But then you have to do this as well, yuck:
CREATE BUFFERPOOL bp32 PAGESIZE 32K;
CREATE SYSTEM TEMPORARY TABLESPACE tsp32 PAGESIZE 32K BUFFERPOOL bp32;
A saner C implementation
#include <sqludf.h>
#ifdef __cplusplus
extern "C"
#endif
void SQL_API_FN ReverseSBCP(SQLUDF_VARCHAR *inVarchar,
SQLUDF_VARCHAR *outVarchar,
SQLUDF_SMALLINT *inVarcharNullInd,
SQLUDF_SMALLINT *outVarcharNullInd,
SQLUDF_TRAIL_ARGS)
{
int inLen, inPos, outPos;
if (*inVarcharNullInd == -1)
{
*outVarcharNullInd = -1;
}
else
{
inLen = strlen(inVarchar);
for (inPos = 0, outPos = inLen -1; inPos < inLen; inPos++, outPos--)
{
outVarchar[outPos] = inVarchar[inPos];
}
outVarchar[inLen] = '\0';
*outVarcharNullInd = 0;
}
return;
}