Character with Bit/hex confusion in DB2 - sql

This works:
SELECT TASKT_ID FROM DATA . TASKT WHERE TASK_WEB_IDENTIFIER = CAST ( HEXTORAW ( '0213725501A421D384233E5001' ) AS CHAR ( 26 ) ) ;
Since that work I put it into the procedure:
BEGIN
DECLARE GET_TASKT_ID_BY_TASK_WEB_IDENTIFIER_C1 CURSOR WITH RETURN FOR
SELECT TASKT_ID FROM DATA . TASKT WHERE TASK_WEB_IDENTIFIER = CAST ( HEXTORAW ( P_WEB_IDENTIFIER ) AS CHAR ( 26 ) ) ;
OPEN GET_TASKT_ID_BY_TASK_WEB_IDENTIFIER_C1 ;
END
The procedure has the one parameter P_WEB_IDENTIFIER which is a CHAR(26) for bit data with the CCSID 65535
However, when I now call it with the string like so:
call PROGRAM . GET_TASKT_ID_BY_TASK_WEB_IDENTIFIER ('0213725501A421D384233E5001');
I get back that the argument for VARBINARY_FUNCTION is invalid by length or data type.
Also, this works:
call PROGRAM . GET_TASKT_ID_BY_TASK_WEB_IDENTIFIER (CAST('0213725501A421D384233E5001' as char(26)));
What Can I do to make sure that string converts with only the string being passed?

What are you using to call the stored procedure?
What version and release of Db2 for i?
In the Run SQL Scripts component of IBM ACS or the older Access for Windows, string literals in your statements are treated as varchar.
Thus the CAST('0213725501A421D384233E5001' as char(26)) makes sense. What doesn't is the error message. Normally, you'd get a procedure not found error as the Db is looking for a procedure named PROGRAM.GET_TASKT_ID_BY_TASK_WEB_IDENTIFIER that takes a varchar parameter and the only thing that exists is a procedure that takes a char(26).
IBM's tools have gotten better at implicitly converting when needed. But I usually go with an explicit conversion when testing manually (as you've done here). Or I just make the parms varchar to start. And convert to character within the procedure if needed.
The char/varchar difference doesn't usually matter to the client code, as it can be specific in it's type definitions. It's only a factor for interactive tools like ACS that are executing dynamic statements.

Related

**** 04:04:32 TPT10508: RDBMS error 3857: Cannot use value (or macro parameter) to match '<column_name>'

**** 04:04:32 TPT10508: RDBMS error 3857: Cannot use value (or macro parameter) to match '<column_name>'.
facing this issues while
executing tpt to load data from csv to Teradata DB. Could you please
help me in resolving this issue.
simple cast logic is used to convert data type from Varchar to decimal and timestamp(0).
and if i hardcode the value like (cast(20.0) as decimal(12,2) ) its working fine.
Failure case cast(column_nm) as decimal(12,2) .

Stripping out non-digits - SQL0171 Argument of function TRANSLATE not valid

I'm trying to extract the first ten digit numbers of a phone number, ending up with a 10-digit (or less) number.
I need to use whitelisting, not blacklisting, due to special characters having been used. e.g. "á(123) 555-4567 Toll Free:á(891) 0" must become 1235554567.
I'm trying to use https://stackoverflow.com/a/37685384.
However, when I try to use this:
TRANSLATE(SFCONTACT.PHONE,'',TRANSLATE(SFCONTACT.PHONE,'','1234567890',''),'') as clean
I get
Message: [SQL0171] Argument 04 of function TRANSLATE not valid.
One of the comments said that using spaces instead of empty strings removed that. However, for me, trying:
TRANSLATE(SFCONTACT.PHONE,' ',TRANSLATE(SFCONTACT.PHONE,' ','1234567890',' '),' ') as clean
gives:
Message: [SQL0171] Argument 03 of function TRANSLATE not valid.
How can I accomplish this?
Running an AS400 DB2, IBM version V7R1M0
EDIT (Not sure if this should be a separate Question or not)
I tried this as suggested:
SUBSTR(REGEXP_REPLACE(PHONE, '[\D]', ''),1,10) AS MAINPHONE,
And at first it seemed to work; I was able to create a view, BBICNTMIG
However, when I try to insert into a table using that view:
INSERT INTO AMMLIBC.BBICONTACT
(COMPANY,CUSNO,SHIPTO,HONORIFICFK,FIRSTNAME,LASTNAME,EMAIL,MAINPHONE,TYPEFK,PROSPECTFK,CREATEDBY,CREATEDAT)
SELECT COMPANY,CUSNO,SHIPTO,HONORIFICFK,FIRSTNAME,LASTNAME,EMAIL,MAINPHONE,TYPEFK,PROSPECTFK,CREATEDBY,CREATEDAT
FROM AMMLIBC.BBICNTMIG
it gives:
Message: [SQL0420] Character in CAST argument not valid. Cause . . . . . : A character in the argument for the CAST function was not correct. Recovery . . . : Change the result data type to one that recognizes the characters in the CAST argument, or change the argument to contain a valid representation of a value for the result data type. Try the request again.
If I remove the phone numbers from the insert (taking default value of null instead), then the INSERT succeeds, so I know it's the phone number causing this.
The column type in the destination table is NUMERIC(10,0). I tried using this, but no change:
CAST(SUBSTR(REGEXP_REPLACE(PHONE, '[\D]', ''),1,10) AS NUMERIC(10,0)) AS MAINPHONE,
Further info:
I tried casting to char before casting to numeric. No change.
I tried adding a where clause (both "mainphone is null" and "mainphone is not null" do this) and the error message changes to:
Message: [SQL0802] Data conversion or data mapping error. Cause . . . . . : Error type 6 has occurred. [...] 6 -- Numeric data that is not valid.
The TRANSLATE function doesn't work correctly for non-ascii characters.
Use the following instead:
SELECT substr(
-- xmlcast(xmlquery('fn:replace($s, "[^\d]", "")' passing PHONE as "s") as varchar(4000)) -- DB2 for LUW
regexp_replace(PHONE, '[^\d]', '') -- DB2 for LUW 11.1 & DB2 for IBM i
, 1, 10)
FROM TABLE(VALUES
'á(123) 555-4567 Toll Free:á(891) 0'
, 'á(123) 555-'
) SFCONTACT(PHONE);
Platform & version of Db2 is important...
Db2 for i 7.2, for instance, gives me
Cause . . . . . : Parameter 3 specified in function TRANSLATE is not valid for use for reason code 1. The reason codes and their meanings follow:
1 -- Parameter must be a string constant.
2 -- Parameter must be an integer constant.
3 -- Parameter must be a numeric constant.
4 -- Parameter's length is too long.
5 -- Parameter's value is out of range.
6 -- Parameter must be a valid CCSID.
7 -- Parameter cannot be a parameter marker.
8 -- Parameter's data type is not supported by the built-in function.
9 -- Parameter cannot reference a column with an active column mask since the function is not secured.
Recovery . . . : Refer to the DB2 for IBM i SQL Reference topic collection in the Database category in the IBM i Information Center book, http://www.ibm.com/systems/i/infocenter/ for more information on functions. Correct the parameter specified for the function. Try the request again.
Using "FETCH FIRST _ ROWS ONLY" and binary search, I found the problem.
The phone number it was trying to parse was "PLEASE VERIFY CONTACT AND EMAIL". Which, stripping out digits, turns into empty string... which does not convert well into NUMERIC(10,0).
So, this fixed the problem:
CASE
WHEN TRIM(REGEXP_REPLACE(PHONE, '[\D]', '')) = '' THEN NULL
ELSE CAST(SUBSTR(REGEXP_REPLACE(PHONE, '[\D]', ''),1,10) AS NUMERIC(10,0))
END AS MAINPHONE,

SSIS to handle SQL binary data type

I am strugling wiith handling a sql binary(8) data type.
No matter what I try to do with it inside the SSIS package, it always fails with an error of: "Invalid cast specification"
Let me describe what I am tying to do in details:
I have a single row that I am assigning to a variable in a SQL Task in the control flow.
select max(LastRowVersion as bigint) as MinRV from MyTable
LastRowVersion is of datatype binary(8).
2.Then I am assigning the result to variable - User::MaxRowVersion
If I configure MaxRowVersion to be of String or Object data type, then this part works fine.
3.Next I am opening a data flow task with the following select statement:
select fields
from AnotherTable
where LastRowVersion > ?
and assigning User::MaxRowVersion to the query.
Again LastRowVersion is of datatype binary(8) in the table - AnotherTable.
Here is where I am getting the error that I mentioned above.
I have tried various types of playing with the DT_BYTES cast type in the expression of the User::MaxRowVersion variable, but it is failing.
I have also read that there is a possibility to open a C# script task to handle it or that Dynamic SQL can help, but I would rather keep the solution as simple as possible with no scripting if possible.
Thanks for the help,
Dani
Have you tried this?
Keep MaxRowVersion as a Sting data type
Cast the variable reference in the SQL statement
Example:
"
SELECT my_field
FROM my_table
WHERE LastRowVersion > CAST('" + #[User::MaxRowVersion] + "' as MyDataType);
"

Bind variables in case statement in MonetDB

I seem to have come across a strange restriction in using bind variables in MonetDB. If i use bind variables in the normal way by saying where field=${var} then it works. But not in this case:
Here is a sample:
select case when ${Brand} = 'All'
And here is the error:
EXEC: wrong type for argument 1 of prepared statement: char, expected char
Using the latest version of the jdbc driver (2.9) via Pentaho.
Casting to char doesnt work either.
However casting both sides to Varchar does work i.e.:
cast(${Brand} as varchar(100)) = cast('All' as varchar(100))
So I guess char's are just a bit funky in MonetDB

Call a stored procedure, into another stored procedure

I have a procedure, that insert a line into one of my table.
After the INSERT in the procedure, I want to find all the lines into another table, and then, call the insert procedure of the second table.
So I have all the first procedure that works fine
P_INSERT_TABLE1
INSERT INTO TABLE1
...
COMMIT;
FOR record_po IN (SELECT C3, ...
FROM T_TABLE2
WHERE id = v_id)
LOOP
P_INSERT_TABLE2(record_po.C3, ...);
END LOOP;
All "in parameters" for P_INSERT_TABLE2 are VARCHAR2, so I make a "to_char" for each column are not varchar2 :
P_INSERT_TABLE2(pi_id,
record_po.C3,
record_po.C4,
record_po.C5,
record_po.C6,
record_po.C7,
to_char(record_po.C8, 'DD/MM/YYYY');
Here, pi_id, is one of the in parameters of P_INSERT_TABLE1, in VARCHAR2.
So now, I have this error message :
Erreur(357,1): PLS-00306: number or args types wrong in the call of P_INSERT_TABLE2
I don't understand, why P_INSERT_TABLE2 don't accept parameters, while there are all the good types in the good order?
If I call the procedure like "call P_INSERT_TABLE2(...)" I have an error like :
Erreur(357,9): PLS-00103: Symbol "P_INSERT_TABLE2" instead one of this symbols : := . ( # % ; immediate Symbole ":="
create or replace
PROCEDURE P_INSERT_TABLE2 (
pi_id IN VARCHAR2
,pi_C3 IN VARCHAR2
,pi_C4 IN VARCHAR2
,pi_C5 IN VARCHAR2
,pi_C6 IN VARCHAR2
,pi_C7 IN VARCHAR2
,pi_C8 IN VARCHAR2
,pmessage OUT NOCOPY VARCHAR2
)
Thanks for helping.
The declaration of P_INSERT_TABLE2 is invalid. You can't have 5 input parameters all named pi_C4. Since you're not getting a compilation error creating that procedure, I'll guess that this was a bug that was introduced posting the question here rather than something that is actually in the code.
According to the declaration of P_INSERT_TABLE2, the procedure takes 7 input parameters and one output parameter. In the code you posted, you appear to be passing in 7 input parameters but you are not passing in a variable for the output parameter. It appears that you need something like
P_INSERT_TABLE2(pi_id,
record_po.C3,
record_po.C4,
record_po.C5,
record_po.C6,
record_po.C7,
to_char(record_po.C8, 'DD/MM/YYYY'),
<<some local variable for the output parameter>> );
Beyond the syntax errors, I am extremely dubious when I see someone taking a perfectly good DATE, casting it to a string, and then passing that to a procedure. That implies either that P_INSERT_TABLE2 is going to turn around and convert the string back to a date, which means that you're doing extra work and have introduced additional points where the conversions can fail, or that you are going to write the string representation of a date to a table. Neither of these implications are good.
I am also highly dubious of any procedure that has an OUT parameter named pMessage. That tends to imply that you're not using exceptions properly and that you're passing an error message back rather than throwing an exception if your code encounters an error. That virtually always leads to much more brittle code that is much more difficult to debug than when you use proper exceptions.