Error: DB2 Stored procedure with the error A value is not compatible with the data type of its assignment target. Target name is "C1" - db2

While creating the stored procedure I am getting the error
"A value is not compatible with the data type of its assignment target. Target name is "C1".. SQLCODE=-408, SQLSTATE=42821, DRIVER=4.19.56"
Help me to create a stored procedure with cursor variable
CREATE OR REPLACE TYPE DE_ROW_T as row ( C1 INTEGER,C2 VARCHAR(100),C2 CHAR(1));
CREATE OR REPLACE TYPE C_ID_CURSOR_T as DE_ROW_T CURSOR;
CREATE OR REPLACE PROCEDURE "SP_CURTEST"
LANGUAGE SQL
BEGIN
DECLARE V_ROW DE_ROW_T;
DECLARE C1 C_ID_CURSOR_T;
SET C1 = CURSOR FOR
SELECT DISTINCT
COL1,COL2,COL3
FROM
MYTABLE
WHERE COL1=101;
OPEN C1;
FETCH C1 INTO V_ROW;
END;

Your table DDL must match the row type in datatype and lengths, otherwise you will get exceptions trying to fit the wrong data into your rowtype variable.
The following script shows how you can see the stored-procedure operating with Db2-LUW v11.5.4.0 on Linux, via printing out the progress as debugging tool. You can also debug stored procedures with other GUI tools, including IBM Data Studio.
--#SET TERMINATOR ;
CREATE OR REPLACE TYPE DE_ROW_T as row ( C1 INTEGER,C2 VARCHAR(100),C3 CHAR(1));
CREATE OR REPLACE TYPE C_ID_CURSOR_T as DE_ROW_T CURSOR;
drop table if exists mytable;
create table mytable(col1 integer, col2 varchar(100), col3 char(1));
insert into mytable(col1,col2,col3) values(101,'abcd','a');
--#SET TERMINATOR #
set serveroutput on#
CREATE OR REPLACE PROCEDURE "SP_CURTEST"
LANGUAGE SQL
specific curtest
BEGIN
DECLARE V_ROW DE_ROW_T;
DECLARE C1 C_ID_CURSOR_T;
SET C1 = CURSOR FOR SELECT DISTINCT COL1,COL2,COL3 FROM MYTABLE WHERE COL1=101;
call dbms_output.put_line('opening c1');
OPEN C1;
call dbms_output.put_line('opened c1');
FETCH C1 INTO V_ROW;
call dbms_output.put_line('fetched c1: '||varchar(v_row.c1)||' , '||trim(v_row.c2)||' , '||v_row.c3);
END
#
call sp_curtest()#
IF you run the above script via the db2 CLP at the command line, it will show the output below:
$ db2 -tvf sp_so_8.sql
CREATE OR REPLACE TYPE DE_ROW_T as row ( C1 INTEGER,C2 VARCHAR(100),C3 CHAR(1))
DB20000I The SQL command completed successfully.
CREATE OR REPLACE TYPE C_ID_CURSOR_T as DE_ROW_T CURSOR
DB20000I The SQL command completed successfully.
drop table if exists mytable
DB20000I The SQL command completed successfully.
create table mytable(col1 integer, col2 varchar(100), col3 char(1))
DB20000I The SQL command completed successfully.
insert into mytable(col1,col2,col3) values(101,'abcd','a')
DB20000I The SQL command completed successfully.
set serveroutput on
DB20000I The SET SERVEROUTPUT command completed successfully.
CREATE OR REPLACE PROCEDURE "SP_CURTEST"
LANGUAGE SQL
specific curtest
BEGIN
DECLARE V_ROW DE_ROW_T;
DECLARE C1 C_ID_CURSOR_T;
SET C1 = CURSOR FOR SELECT DISTINCT COL1,COL2,COL3 FROM MYTABLE WHERE COL1=101;
call dbms_output.put_line('opening c1');
OPEN C1;
call dbms_output.put_line('opened c1');
FETCH C1 INTO V_ROW;
call dbms_output.put_line('fetched c1: '||varchar(v_row.c1)||' , '||trim(v_row.c2)||' , '||v_row.c3);
END
DB20000I The SQL command completed successfully.
call sp_curtest()
Return Status = 0
opening c1
opened c1
fetched c1: 101 , abcd , a
$

Related

DB2 Logging in stored procedure

Is it possible to create log outputs in a specific mode like debug or info within a stored procedure?
I just know only awared about the cmd DBMS_OUTPUT.PUT_LINE. But I need it with specification of the log level.
--#SET TERMINATOR #
CREATE TABLE LOG (TS TIMESTAMP NOT NULL, MSG VARCHAR (100))#
CREATE OR REPLACE PROCEDURE LOGGER (P_MSG VARCHAR (100))
AUTONOMOUS
BEGIN
INSERT INTO LOG (TS, MSG) VALUES (GENERATE_UNIQUE()::TIMESTAMP, P_MSG);
END#
CREATE TABLE TEST (I INT)#
CREATE OR REPLACE TRIGGER TEST_AIR
AFTER INSERT ON TEST
REFERENCING NEW AS N
FOR EACH ROW
BEGIN ATOMIC
CALL LOGGER ('Start of insertion: ' || N.I);
CALL DBMS_ALERT.SLEEP (3);
CALL LOGGER ('End of inserion: ' || N.I);
END#
INSERT INTO TEST VALUES 1, 2#
SELECT * FROM LOG ORDER BY TS#
TS
MSG
2023-02-13-17.41.57.098209
Start of insertion: 1
2023-02-13-17.42.00.115693
End of inserion: 1
2023-02-13-17.42.00.137199
Start of insertion: 2
2023-02-13-17.42.03.163761
End of inserion: 2

Postgresql 13 Stored Procedure issue [duplicate]

I am trying to create and populate a temp table inside a procedure to save some intermediate state of the data I am working with.
I have created an example code to explain what I am trying to do:
CREATE OR REPLACE PROCEDURE etl.my_test_procedure()
LANGUAGE sql
AS
$$
CREATE TEMP TABLE IF NOT EXISTS my_temp(
var1 VARCHAR(255),
var2 VARCHAR(255)
) ON COMMIT DROP;
INSERT INTO my_temp (
var1,
var2
)
SELECT
table_schema,
column_name
FROM information_schema.columns;
SELECT
*
FROM my_temp
$$
When trying to create this Stored Procedure the database returns this error message:
ERROR: relation "my_temp" does not exist
LINE 10: INSERT INTO my_temp (
^
SQL state: 42P01
Character: 171
PD: My version of Postgres is 13.3
You would have to use plpgsql instead of sql
CREATE OR REPLACE FUNCTION my_test_procedure()
RETURNS TABLE(var1 VARCHAR(255), var2 VARCHAR(255))
AS
$$
DECLARE
BEGIN
CREATE TEMP TABLE IF NOT EXISTS my_temp(
var1 VARCHAR(255),
var2 VARCHAR(255)
) ON COMMIT DROP;
INSERT INTO my_temp (
var1,
var2
)
SELECT
table_schema,
column_name
FROM information_schema.columns;
RETURN QUERY SELECT *
FROM my_temp;
END;
$$ LANGUAGE plpgsql;
The reason for the error is that SQL functions are parsed when they are created. You can avoid that by setting the parameter check_function_bodies to off.
But that doesn't help you much: it allows you to create the function, but you will end up with the same error when you execute the procedure, since all statements are parsed when the function starts, and my_temp does not exist at that time.
The solution is to use PL/pgSQL, like JGH's answer suggests.

Temp table inside a Procedure in Postgres

I am trying to create and populate a temp table inside a procedure to save some intermediate state of the data I am working with.
I have created an example code to explain what I am trying to do:
CREATE OR REPLACE PROCEDURE etl.my_test_procedure()
LANGUAGE sql
AS
$$
CREATE TEMP TABLE IF NOT EXISTS my_temp(
var1 VARCHAR(255),
var2 VARCHAR(255)
) ON COMMIT DROP;
INSERT INTO my_temp (
var1,
var2
)
SELECT
table_schema,
column_name
FROM information_schema.columns;
SELECT
*
FROM my_temp
$$
When trying to create this Stored Procedure the database returns this error message:
ERROR: relation "my_temp" does not exist
LINE 10: INSERT INTO my_temp (
^
SQL state: 42P01
Character: 171
PD: My version of Postgres is 13.3
You would have to use plpgsql instead of sql
CREATE OR REPLACE FUNCTION my_test_procedure()
RETURNS TABLE(var1 VARCHAR(255), var2 VARCHAR(255))
AS
$$
DECLARE
BEGIN
CREATE TEMP TABLE IF NOT EXISTS my_temp(
var1 VARCHAR(255),
var2 VARCHAR(255)
) ON COMMIT DROP;
INSERT INTO my_temp (
var1,
var2
)
SELECT
table_schema,
column_name
FROM information_schema.columns;
RETURN QUERY SELECT *
FROM my_temp;
END;
$$ LANGUAGE plpgsql;
The reason for the error is that SQL functions are parsed when they are created. You can avoid that by setting the parameter check_function_bodies to off.
But that doesn't help you much: it allows you to create the function, but you will end up with the same error when you execute the procedure, since all statements are parsed when the function starts, and my_temp does not exist at that time.
The solution is to use PL/pgSQL, like JGH's answer suggests.

Trying to use temporary table in IBM DB2 and facing issues

I am getting the following error while creating a stored procedure for testing purpose:
SQL Error [42601]: An unexpected token "DECLARE GLOBAL TEMPORARY TABLE
SESSION" was found following "RSOR WITH RETURN FOR". Expected tokens may include: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.21.29
Code:
CREATE OR REPLACE PROCEDURE Test ( IN GE_OutPutType SMALLINT)
----------------------------------------------------------------------------------------------------
DYNAMIC RESULT SETS 1 LANGUAGE SQL
BEGIN
DECLARE C CURSOR WITH RETURN FOR DECLARE GLOBAL TEMPORARY TABLE
SESSION.TEMP (DATE CHAR(10) NOT NULL,
SALARY DECIMAL(9,
2) ,
COMM DECIMAL(9,
2));
INSERT
INTO
SESSION.TEMP (DATE,
SALARY,
COMM) SELECT
VARCHAR_FORMAT(CURRENT_DATE,
'MM/DD/YYYY'),
10.2,
11.5
FROM
sysibm.sysdummy1
IF GE_OutPutType = 1
BEGIN
SELECT
*
FROM
TEMP
ELSEIF GE_OutPutType = 2 SELECT
'HEADER' CONCAT SPACE(1979) CONCAT 'H'
FROM
sysibm.sysdummy1
END OPEN C;
END
Your syntax is not valid.
You must declare your temporary table independently of your cursor.
You cannot combine these in a single statement.
Use dynamic-SQL features to achieve what you need.
Use instead the format:
Declare c1 cursor with return to caller for Statement1
and
set v_cursor_text = 'select ... from session.temp ; `
then use
prepare Statement1 from v_cursor_text;
and before you exit the stored procedure you need to leave the cursor opened:
open c1;
Do study the Db2 online documentation to learn more about these features.
Here is a small fragment of your procedure showing what I mean:
CREATE OR REPLACE PROCEDURE mytest ( IN GE_OutPutType SMALLINT)
DYNAMIC RESULT SETS 1
LANGUAGE SQL
specific mytest
BEGIN
DECLARE v_cursor_text varchar(1024);
DECLARE C1 CURSOR WITH RETURN FOR Statement1;
DECLARE GLOBAL TEMPORARY TABLE SESSION.TEMP (
DATE CHAR(10) NOT NULL,
SALARY DECIMAL(9,
2) ,
COMM DECIMAL(9,
2))
with replace on commit preserve rows not logged;
INSERT INTO SESSION.TEMP (DATE, SALARY, COMM)
SELECT VARCHAR_FORMAT(CURRENT_DATE, 'MM/DD/YYYY'),
10.2,
11.5
FROM sysibm.sysdummy1 ;
if GE_OutPutType = 1
then
set v_cursor_text = 'select * from session.temp';
end if;
if GE_OutPutType = 2
then
set v_cursor_text = 'select ''header'' concat space(1979) concat ''H'' from sysibm.sysdummy1';
end if;
prepare Statement1 from v_cursor_text;
open c1;
END#

Syntax error in defining a stored procedure in DB2

I'm defining a simple stored procedure in DB2 as follows but it gives me syntax error
CREATE OR REPLACE PROCEDURE Schema1.TESTSP1 ()
DYNAMIC RESULT SETS 1
P1: BEGIN
if( exists(
select 1 from syscat.tables where tabschema = 'Schema' and tabname = 'SPTEST'
)) then
drop table Schema.SPTEST ;
create table Schema.SPTEST as
(select * from Schema.XYZ) WITH DATA ;
end if;
END P1
What is wrong here?
You need to study the IBM example stored procedures for SQL PL.
Get the sample procedures working in your environment to build knowledge and skills.
You need to understand the difference between dynamic-sql and static-SQL and when to use either one.
You need to add exception handlers for any exceptions.
As you specified that it returns one result-set you need to open a cursor on that final result-set.
The examples below are for the Db2-LUW Version 11.1.3.3 CLP (command line processor), i.e. on Microsoft Windows that is the what runs when you open db2cwadmin.bat, and on Linux/Unix the bash/ksh shell:
Note: the WITH DATA requires Db2-LUW 11.1.3.3, older versions supported only WITH NO DATA. If you cannot upgrade, then use instead 'CREATE TABLE ... LIKE ...' followed by a separate statement INSERT INTO ... SELECT ...FROM ...
Here is a skeleton resembling your example, using static SQL on Db2-LUW V11.1.3.3:
--#SET TERMINATOR #
CREATE OR REPLACE PROCEDURE Schema1.TESTSP1 ()
DYNAMIC RESULT SETS 1
P1: BEGIN
DECLARE SQLCODE integer;
DECLARE table_exists integer default 0;
select 1 into table_exists from syscat.tables where tabschema = 'SOMESCHEMA' and tabname = 'SPTEST';
if table_exists = 1
then
drop table SOMESCHEMA.SPTEST ;
create table SOMESCHEMA.SPTEST as (select * from SCHEMA.SPTEST ) with data ;
end if;
END P1
#
Here is a skeleton which resembles your example but uses dynamic-SQL on Db2-LUW V11.1.3.3, which would be useful if you don't know in advance the table/column names and they are available in parameters to the stored procedure (not shown) in which case you can dynamically build the SQL and execute it:
--#SET TERMINATOR #
CREATE OR REPLACE PROCEDURE Schema1.TESTSP1 ()
DYNAMIC RESULT SETS 1
P1: BEGIN
DECLARE SQLCODE integer;
DECLARE table_exists integer default 0;
select 1 into table_exists from syscat.tables where tabschema = 'SOMESCHEMA' and tabname = 'SPTEST';
if table_exists = 1
then
execute immediate('drop table SOMESCHEMA.SPTEST') ;
execute immediate('create table SOMESCHEMA.SPTEST as (select * from SCHEMA.SPTEST ) with data') ;
end if;
END P1
#