I have a DB2 stored procedures to get n number of sequence values and then combine them into a single comma delimited string and return it. The concat function in the stored procedure is not working as expected.
CREATE PROCEDURE REFWTX.GET_SEQ_VALUES (in numb integer, OUT SEQVALUES VARCHAR(10000))
LANGUAGE SQL
SPECIFIC GET_SEQ_VALUES
BEGIN
DECLARE SEQ_VAL Integer;
DECLARE CUR_COUNT INTEGER;
SET CUR_COUNT=1;
WHILE (CUR_COUNT <= numb) DO
SELECT NEXTVAL FOR REFWTX.ACK_999_INTR_CTRL_NO_SEQ INTO SEQ_VAL FROM SYSIBM.SYSDUMMY1;
set SEQVALUES = SEQVALUES|| ',' || CHAR(SEQ_VAL);
SET CUR_COUNT=CUR_COUNT+1;
END WHILE;
return;
END
The portion of the procedure:
set SEQVALUES = SEQVALUES|| ',' || CHAR(SEQ_VAL);
is not working as expected. How do I concatenate strings in stored procedures?
You haven't told us how it is "not working as expected". Example inputs and output would be useful.
My guess would be that since you never initialize SEQVALUES, it is set to NULL and concatenating anything with NULL gives you NULL.
Also, instead of
SELECT NEXTVAL FOR REFWTX.ACK_999_INTR_CTRL_NO_SEQ INTO SEQ_VAL FROM SYSIBM.SYSDUMMY1;
why not use
VALUES NEXTVAL FOR REFWTX.ACK_999_INTR_CTRL_NO_SEQ INTO SEQ_VAL;
Related
I am trying to write a stored procedure in AWS Redshift SQL and one of my parameters needs the possibility to have an integer list (will be using 'IN(0,100,200,...)' inside there WHERE clause). How would I write the input parameter in the header of the procedure so that this is possible (if at all?)
I've tried passing them in as a VARCHAR "integer list" type thing but wasn't sure then how to parse that back into ints.
Update: I found a way to parse the string and loop through it using the SPLIT_PART function and store all of those into a table. Then just use a SELECT * FROM table with the IN() call
What I ended up doing was as follows. I took in the integers that I was expecting as a comma-separated string. I then ran the following on it.
CREATE OR REPLACE PROCEDURE test_string_to_int(VARCHAR)
AS $$
DECLARE
split_me ALIAS FOR $1;
loop_var INT;
BEGIN
DROP TABLE IF EXISTS int_list;
CREATE TEMPORARY TABLE int_list (
integer_to_store INT
);
FOR loop_var IN 1..(REGEXP_COUNT(split_me,',') + 1) LOOP
INSERT INTO int_list VALUES (CAST(SPLIT_PART(split_me,',',loop_var) AS INT));
END LOOP;
END;
$$ LANGUAGE plpgsql;
So I would call the procedure with something like:
CALL test_string_to_int('1,2,3');
and could do a select statement on it to see all the values stored into the table. Then in my queries the need this parameter I ran:
.........................
WHERE num_items IN(SELECT integer_to_store FROM int_list);
i am writing a procedure function in phpmyadmin for attendance purpose.But i am getting wrong information from function if condition.
below is the sample code for procedure and functions without if.
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `USP_GetEmployeeAttendanceReport`(IN selectedIndex int,IN searchText nvarchar(20),IN selectedDate datetime)
BEGIN
select FN_CheckEmpAttendanceStatus(selectedIndex,selectedDate);
END
Function FN_CheckEmpAttendanceStatus
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `FN_CheckEmpAttendanceStatus`(cardid varchar(150),selectedDate datetime) RETURNS int(11)
BEGIN
DECLARE result INT;
set result=(select count(*) from iotrans where CARDID=cardid and dt=selectedDate);
return result;
END
but from function i am getting garbage values (i.e 80,0,81,82....).thanks in advance
The problem is most likely caused by the fact that you use the same name cardid for a function parameter as for a column in iotrans, thus MySQL can't tell them apart and condition WHERE CARDID=cardid always evaluates as TRUE.
Always give distinct names to routine parameters. I'd suggest to come up with some naming scheme, e.g. putting a underscore in front of the name of a parameter, so that you do that consistently across all your code and can easily tell whether it's a parameter or a column name.
One more thing usage of result variable is unnecessary overhead in your case as is BEGIN...END block.
That being said your function might've looked like this
CREATE DEFINER=`root`#`localhost`
FUNCTION FN_CheckEmpAttendanceStatus
(
_cardid varchar(150),
_selectedDate datetime
) RETURNS INT(11)
RETURN
(
SELECT COUNT(*)
FROM iotrans
WHERE cardid = _cardid
AND dt = _selectedDate
);
I am new to IBM db2 stored procedure, what I am trying to do is to get the values of a column from a table and build a select query based on these values, this is what I have tried, not sure how to proceed
CREATE TYPE currencySymbols AS VARCHAR(20) ARRAY[100]#
CREATE PROCEDURE ins_curr_ano(IN crsymbol VARCHAR(20), IN cost1 integer, IN cost2 integer, IN teirId integer)
BEGIN
DECLARE currencies currencySymbols;
DECLARE maxCount INTEGER DEAFULT 0;
set currencies = ARRAY[SELECT distinct(CURR_SYMBOL) as currencySymbols FROM CURRENCY_MAPPING];
set maxCount = CARDINALITY(currencies);
for i in 1..maxCount loop
dbms_output.put_line(i);
end loop;
END#
Below is the error I am getting:
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0104N An unexpected token "loop" was found following "for i in
1..maxCount". Expected tokens may include: "(". LINE NUMBER=13.
SQLSTATE=42601
That for ... loop statement in your code has PL/SQL syntax, while everything else has DB2 SQL PL syntax. You cannot mix the two in the same routine.
Techies--
I'm getting sql0204 XML in *LIBL type *SQLUDT not found on an i db2 6.1 install when I try to deploy a stored proc I know works on Linux v9.7. The reason I am attempting to get this to work is because I really need to pass a table (or array) variable. I couldn't find a way to send a multi-dim array to a sproc on the 6.1 v of i, so I thought I'd try getting around that with an xml doc. But that failed too... Does anyone have any advice for me on how to solve this issue?
Here's the sproc that works on v9.7,Linux:
CREATE PROCEDURE HCMDEV.EMP_MULTIPLE_XML (IN DOC XML)
DYNAMIC RESULT SETS 1
READS SQL DATA
LANGUAGE SQL SPECIFIC EMP_MULTIPLE_XML
P1: BEGIN
DECLARE CSR1 CURSOR WITH RETURN FOR
SELECT emp.EMPID,
emp.FIRSTNAME,
emp.LASTNAME,
emp.DIVISION,
emp.DISTRICT,
emp.LOCATION,
emp.OPERATIONALAREA,
emp.TERMDATE,
emp.REHIREDATE,
emp.HIREDATE,
emp.ADDRESSLINE1,
emp.ADDRESSLINE2,
emp.CITY,
emp.STATE,
emp.ZIPCODE,
emp.TELEPHONE1,
emp.POSITIONCODE,
emp.POSITIONTITLE,
emp.HIRECODE
FROM HCMDEV.EMPLOYEE emp
WHERE EMP.EMPID IN
(SELECT X.EMPID
FROM XMLTABLE('$d/EMPLOYEE/EMPID' PASSING DOC AS "d" COLUMNS EMPID CHAR(9) PATH '.') AS X);
OPEN CSR1;
END P1
For those following this thread, xmltable is NOT available until V7R1. The workaround is to create a stored proc that accepts as the IN paramater a CLOB datatype. In my case, I pass a long string with commas to separate the values for the empid. That works just fine.
Here's a sampling:
CREATE PROCEDURE HCMDEV.EMP_MULT (IN emp_array CLOB(2M))
DYNAMIC RESULT SETS 1
READS SQL DATA
LANGUAGE SQL SPECIFIC EMP_MULT
P1: BEGIN
-- #######################################################################
-- # Returns specific employees based on incoming clob array
-- #######################################################################
DECLARE v_dyn varchar(10000);
DECLARE v_sql varchar(10000);
DECLARE cursor1 CURSOR WITH RETURN FOR v_dyn;
SET v_sql =
'SELECT
emp.EMPID,
emp.FIRSTNAME,
emp.LASTNAME
FROM HCMDEV.EMPLOYEE emp
WHERE emp.EMPID IN (' || emp_array || ')';
PREPARE v_dyn FROM v_sql;
OPEN cursor1;
END P1
I am trying to write a stored procedure to concatenate multiple rows of text together to return it as a single string. For example:
CREATE TABLE TEST (
ID INTEGER,
SEQ INTEGER,
TEXT VARCHAR(255));
COMMIT;
INSERT INTO TEST (ID, SEQ, TEXT) VALUES (1, 1, "LINE 1");
INSERT INTO TEST (ID, SEQ, TEXT) VALUES (1, 2, "LINE 2");
INSERT INTO TEST (ID, SEQ, TEXT) VALUES (1, 3, "LINE 3");
COMMIT;
SET TERM !!;
CREATE PROCEDURE concat_names (iID INTEGER)
RETURNS (CONCAT VARCHAR(2000))
AS
DECLARE VARIABLE name VARCHAR(255);
BEGIN
CONCAT = '';
FOR SELECT TEXT FROM TEST where id=:iID INTO :name
DO BEGIN
CONCAT = CONCAT || name;
END
END!!
SET TERM ;!!
commit;
However when I run:
select concat from concat_names(1);
It always returns zero rows.
Any ideas?
You forget for SUSPEND. Your proc should look like this:
SET TERM !!;
CREATE PROCEDURE concat_names (iID INTEGER)
RETURNS (CONCAT VARCHAR(2000))
AS
DECLARE VARIABLE name VARCHAR(255);
BEGIN
CONCAT = '';
FOR SELECT TEXT FROM TEST where id=:iID INTO :name
DO BEGIN
CONCAT = CONCAT || name;
END
SUSPEND;
END!!
SET TERM ;!!
You can achieve the same result without stored proc. Use LIST aggregate function:
SELECT LIST(text, '') FROM TEST where id=:iID
Second parameter of LIST is a delimiter. If you call LIST with only field name, then comma ',' will be used to separate values.
In the case the field TEST can ben null and you don't want to set to null the whole result it is useful to use:
CONCAT = CONCAT || coalesce(name,'');
instead of
CONCAT = CONCAT || name;
Without utilizing a Stored Proc and using version Firebird 2.5, the LIST aggregation function will return "Comma-separated string concatenation of non-NULL values in the column"*. Using the aforementioned TEST table, the SQL
SELECT LIST(TEXT)
FROM TEST
returns
LINE 1,LINE 2,LINE 3
This may be of some interest.
*Taken from the Firebird reference page here