update a column inside a stored procedure - stored-procedures

I have two snowflake tables as below
TEST1
create OR REPLACE table TEST1 (
id varchar(100),
name varchar(100),
org VARCHAR(64)
);
INSERT INTO TEST1 values (100, 'ABC', null);
INSERT INTO TEST1 values (200, 'XYZ', null);
INSERT INTO TEST1 values (300, 'VBN', null);
CONTROL
create OR REPLACE table CONTROL (
KEY_COLUMNS VARCHAR,
TABLE_NAME VARCHAR,
org VARCHAR
);
INSERT INTO CONTROL values ('id,name, address','TEST1','Z');
INSERT INTO CONTROL values ('id,name, address','TEST2','T');
I have created a stored procedure which updates column 'org' in TEST1 table with the values from CONTROL table (column org) where table name is TEST1.
CREATE OR REPLACE PROCEDURE TEST(source_tbl VARCHAR)
RETURNS string
LANGUAGE SQL
AS
$$
DECLARE
query1 STRING;
BEGIN
QUERY1 := 'update TEST1 set ORG = (select org from CONTROL WHERE TABLE_NAME = ''source_tbl'');';
EXECUTE IMMEDIATE :QUERY1;
RETURN :QUERY1;
END;
$$;
call TEST((select TABLE_NAME from CONTROL WHERE TABLE_NAME = 'TEST1'));
expected output
My output

The parameter should be bound variable instead of passing as the string constant ''source_tbl'':
CREATE OR REPLACE PROCEDURE TEST(source_tbl VARCHAR)
RETURNS string
LANGUAGE SQL
AS
$$
DECLARE
query1 STRING;
BEGIN
QUERY1 := 'update TEST1 set ORG = (select org from CONTROL WHERE TABLE_NAME = ?);';
EXECUTE IMMEDIATE :QUERY1 USING (SOURCE_TBL);
RETURN :QUERY1;
END;
$$
Related: EXECUTE IMMEDIATE:
EXECUTE IMMEDIATE '<string_literal>'
[ USING (bind_variable_1 [, bind_variable_2 ...] ) ] ;

Related

Dynamic Insert through Teradata Stored procedure

I am trying to run Insert statement to load data into table using Teradata Stored procedure. Here I am trying to Input Table Name, Databasename as Parameter. My stored procedure compiled and ran well. But its not inserting any data into table. Could someone please help me with this. Below is the query I am using..
REPLACE PROCEDURE DB.TEST_SP
(
IN SRC_DB_NM VARCHAR(30)
, IN SRC_TBL_NM VARCHAR(30)
, OUT MESSAGE VARCHAR(200)
)
DYNAMIC RESULT SETS 1
BEGIN
DECLARE QUERY1 VARCHAR(200);
DECLARE RESULT1 VARCHAR(200);
DECLARE REC_COUNT INTEGER DEFAULT 0;
DECLARE STATUS CHAR(10) DEFAULT '00000';
DECLARE C1 CURSOR FOR S1;
DECLARE EXIT HANDLER FOR SQLEXCEPTION,SQLWARNING
BEGIN
SET STATUS = SQLCODE;
IF(TRIM(STATUS)) = '3807' THEN
SET MESSAGE = 'PASSED TABLE '||SRC_DB_NM||'.'||SRC_TBL_NM||' DOES NOT EXIST';
ELSE
SET MESSAGE = 'LOADED';
END IF;
END;
BEGIN
SET QUERY1 ='INSERT INTO TABLE1 SELECT ColX , count(*) from DB.table2 where Col in ( SELECT Col1 FROM ' || SRC_DB_NM || '.' || SRC_TBL_NM || ' where ColY = 999 ) group by 1;' ;
EXECUTE IMMEDIATE QUERY1;
PREPARE S1 FROM QUERY1;
OPEN C1 USING SRC_DB_NM,SRC_TBL_NM;
FETCH C1 INTO RESULT1;
SET MESSAGE = RESULT1;
END;
END;

How to Execute Macro through Stored Procedure

I have created one macro in Teradata, now wish to call that macro through Stored Procedure (in Teradata only). The SQL part belongs to macro.
I wrote this procedure in case if execution of macro is not possible through procedure.
Kindly suggest both the option.
CREATE PROCEDURE MDM_STAGE.match_sqls_proc
(
in fname VARCHAR(30),
in match_frst_name VARCHAR (100),
in lname VARCHAR(30),
in match_last_name VARCHAR (100),
in addr1 VARCHAR(1000),
in zip_cd_base varchar(10),
in email VARCHAR(30),
in phone VARCHAR(30),
out msgs VARCHAR(10)
-- INOUT errstr VARCHAR(30)
)
begin
DECLARE SQLTEXT2 VARCHAR (10) ;
DECLARE TBL_COUNT INT ;
select count (*) into :TBL_COUNT from
(
SELECT
CUST.CUST_ID,
CUST.FRST_NAME,
CUST.MATCH_FRST_NAME,
CUST.LAST_NAME,
CUST.MATCH_LAST_NAME,
CUST.GNDR_TYPE_CD,
STREET_ADDR.ADDR_LN_1_TXT,
STREET_ADDR.ADDR_LN_2_TXT,
STREET_ADDR.ADDR_LN_3_TXT,
cast (coalesce (STREET_ADDR.ADDR_LN_1_TXT,'') || ' ' || coalesce
(STREET_ADDR.ADDR_LN_2_TXT,'' ) as varchar (1000)) as addr,
STREET_ADDR.CITY_NAME,
STREET_ADDR.POSTL_CD,
STREET_ADDR.STREET_ADDR_ID,
STREET_ADDR.ADDR_SBTYPE_CD,
ELCTRNC_ADDR.ELCTRNC_ADDR_ID,
ELCTRNC_ADDR.ELCTRNC_ADDR_SBTYPE_CD,
ELCTRNC_ADDR.ELCTRNC_ADDR_TXT,
TLPHN_NUM.TLPHN_LN_NUM,
TLPHN_NUM.TLPHN_NUM_ID
FROM
MDM_STAGE.REF_CUST_V CUST
LEFT OUTER JOIN
MDM_STAGE.REF_STREET_ADDR_V STREET_ADDR
ON
CUST.CUST_ID = STREET_ADDR.CUST_ID
AND
--RDM_ADDRSIM (STREET_ADDR.ADDR_LN_1_TXT ,'2285Main Street' ) =1
RDM_ADDRSIM ( cast (coalesce (STREET_ADDR.ADDR_LN_1_TXT,'') || ' ' ||
coalesce (STREET_ADDR.ADDR_LN_2_TXT,'' ) as varchar (1000)) ,:addr1) =1
AND
SUBSTR(STREET_ADDR.POSTL_CD,0,6) = (:zip_cd_base)
LEFT OUTER JOIN
MDM_STAGE.REF_ELCTRNC_ADDR_V ELCTRNC_ADDR
ON
CUST.CUST_ID = ELCTRNC_ADDR.CUST_ID
/*AND
STREET_ADDR.ADDR_SBTYPE_CD = ELCTRNC_ADDR.ELCTRNC_ADDR_SBTYPE_CD*/
AND
ELCTRNC_ADDR.ELCTRNC_ADDR_TXT= (:email)
LEFT OUTER JOIN
MDM_STAGE.REF_TLPHN_NUM_V TLPHN_NUM
ON
CUST.CUST_ID = TLPHN_NUM.CUST_ID
/*AND
STREET_ADDR.ADDR_SBTYPE_CD = TLPHN_NUM.ADDR_SBTYPE_CD*/
AND
TLPHN_NUM.TLPHN_LN_NUM = (:phone)
WHERE
(RDM_sndx(COALESCE(CUST.Match_FRST_NAME,CUST.CUST_ID))=RDM_sndx(:match_frst_name)
AND
RDM_sndx(COALESCE(STRTOK(CUST.Match_LAST_NAME,' ',1),CUST.CUST_ID))=RDM_SNDX(:match_last_name)
)
AND
(
TLPHN_NUM.CUST_ID IS NOT NULL
OR
ELCTRNC_ADDR.CUST_ID IS NOT NULL
OR
STREET_ADDR.CUST_ID IS NOT NULL
) A
;
IF ( TBL_COUNT > 0 ) THEN SET SQLTEXT2 = 'Match' ;
ELSE
SET Msgs = 'Non-Match' ;
END IF;
end;
Error message -
SPL1027:E(L88), Missing/Invalid SQL statement'E(3707):Syntax error, expected something like an 'EXCEPT' keyword or an 'UNION' keyword or a 'MINUS' keyword between ')' and the word 'A'.'.
No idea, what to add between the word 'A' and ')'. Tried all the possibility but not successful. Not sure how to pass the value of SQL into the 'count' as later call procedure condition is based on that count only.

DB2 - how to call a stored procedure that returns a result set in another user defined table function

I have a db2 stored procedure that takes in some parameters, gets some data from somewhere and then returns a result set through a cursor.
Now I want to write a table function in db2, that will call this stored procedure, read from the result set and return the data in the result set as a table (eventually I want to use this table function in a join).
I would like to know if this is permitted in db2 (we're using DB2 v10.5), i.e. execute a stored procedure in a table function and fetch and read from the result set from the stored procedure. If so, what is the right syntax for calling the stored procedure and reading the result set inside a table function in db2? Thanks!
Yes, it's possible. See the example below.
--#SET TERMINATOR #
CREATE OR REPLACE PROCEDURE TEST_PROC(P_TABSCHEMA VARCHAR(128))
DYNAMIC RESULT SETS 1
READS SQL DATA
BEGIN
DECLARE C1 CURSOR WITH HOLD WITH RETURN FOR
SELECT TABSCHEMA, TABNAME, COLCOUNT
FROM SYSCAT.TABLES
WHERE TABSCHEMA=P_TABSCHEMA;
OPEN C1;
END#
--CALL TEST_PROC('SYSCAT')#
CREATE OR REPLACE FUNCTION TEST_PROC(P_TABSCHEMA VARCHAR(128))
RETURNS TABLE (
TABSCHEMA VARCHAR(128)
, TABNAME VARCHAR(128)
, COLCOUNT INT
)
READS SQL DATA
BEGIN
DECLARE SQLSTATE CHAR(5);
DECLARE V_TABSCHEMA VARCHAR(128);
DECLARE V_TABNAME VARCHAR(128);
DECLARE V_COLCOUNT INT;
DECLARE V1 RESULT_SET_LOCATOR VARYING;
CALL TEST_PROC(P_TABSCHEMA);
ASSOCIATE RESULT SET LOCATOR (V1) WITH PROCEDURE TEST_PROC;
ALLOCATE C1 CURSOR FOR RESULT SET V1;
L1: LOOP
FETCH C1 INTO V_TABSCHEMA, V_TABNAME, V_COLCOUNT;
IF SQLSTATE<>'00000' THEN LEAVE L1; END IF;
PIPE(V_TABSCHEMA, V_TABNAME, V_COLCOUNT);
END LOOP L1;
CLOSE C1;
RETURN;
END#
SELECT * FROM TABLE(TEST_PROC('SYSCAT'))#
You need to create the DB2 table-function as follows:
CREATE FUNCTION database_schema.function_name ( IN_PARTID VARCHAR(1000) )
RETURNS TABLE ( PARTNO CHAR(25), PARTDS CHAR(30), QUANTITY INT )
BEGIN
RETURN SELECT PARTNO , PARTDS , CASE WHEN QUANTITY > 0 THEN QUANTITY ELSE 0 END QUANTITY
FROM
(
SELECT PARTNO
,MAX(PARTDS) AS PARTDS
,SUM(QUANTITY) AS QUANTITY
FROM database_schema.table_name
WHERE 1=1
AND PARTID = (CAST(IN_PARTID AS INT))
GROUP BY PARTNO
) AA;
END;
Then invoke the table-function as join or straight SQL:
SELECT partno,partds,quantity
FROM TABLE(database_schema.function_name('parameter_1'))

Firebird and stored procedures: if exists then else

I'm trying to create a stored procedure for firebird 2.1 (this is the version which is to be used)
But am getting a bit stuck, so any help is appreciated.
The final version should compare 4 values agains the table, and retreive either the primaryid if the value exists, or create the new entry in the table, and return the new primaryid.
But I get stuck with only one value lookup, and it's not even using the variable yet.
SET TERM ^ ;
CREATE PROCEDURE TESTSP
( A Varchar(64) )
RETURNS
( RESULT Integer )
AS
BEGIN
IF (EXISTS (SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string')) then
SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string' into :primaryid;
result = PRIMARYID;
ELSE
INSERT INTO TABLENAME (FIELD) VALUES ('Some string');
result = gen_id(GEN_TABLEID, 0);
END^
SET TERM ; ^
I get a "Token unknown" for the Else command.
Update after responses:
Now I want to use the 4 variables and return the 4 results.
I think I need a for loop to do so, but with firebird, the for function means something else.
So what would be the way to go?
SET TERM ^ ;
CREATE PROCEDURE TESTSP
( value1 Varchar(64) )
RETURNS
( RESULT1 Integer )
AS
BEGIN
IF (EXISTS (SELECT PRIMARYID FROM TABLENAME WHERE FIELD = :value1)) then
SELECT PRIMARYID FROM TABLENAME WHERE FIELD = value1 into :result1;
ELSE BEGIN
result1 = gen_id(GEN_TABLEID, 1);
INSERT INTO TABLENAME (PRIMARYID, FIELD) VALUES (:result1, :value1);
END
suspend;
END^
SET TERM ; ^
As Tico already answered you have to use begin / end to group multiple statements in then / else part. The error abut column PRIMARYID being unknown is because you reference to it without having declared a local variable for it. Try this:
CREATE PROCEDURE TESTSP ( A Varchar(64) )
RETURNS ( RESULT Integer )
AS
BEGIN
-- initialize the result
Result = NULL;
-- check is the string already in table
SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string' into :Result;
IF (Result is NULL) then
INSERT INTO TABLENAME(PRIMARYID, FIELD) VALUES(gen_id(GEN_TABLEID, 1), 'Some string') RETURNING PRIMARYID INTO :Result;
END^
I think your stored procedure should look like this:
SET TERM ^ ;
CREATE PROCEDURE TESTSP
( A Varchar(64) )
RETURNS ( result Integer )
AS
BEGIN
IF (EXISTS (SELECT PRIMARYID
FROM TABLENAME
WHERE FIELD = 'Some string')) then
SELECT PRIMARYID
FROM TABLENAME
WHERE FIELD = 'Some string'
into :result;
ELSE BEGIN
result = gen_id(GEN_TABLEID, 1);
INSERT INTO TABLENAME
(PRIMARYID, FIELD)
VALUES (:result, 'Some string');
END
END^
SET TERM ; ^
If you have multiple instruction for then and/ or else clause you must use BEGIN ... END-block!
SET TERM ^ ;
CREATE PROCEDURE TESTSP
( A Varchar(64) )
RETURNS
( RESULT Integer )
AS
BEGIN
IF (EXISTS (SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string')) then
BEGIN
SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string' into :primaryid;
result = PRIMARYID;
END
ELSE
BEGIN
INSERT INTO TABLENAME (FIELD) VALUES ('Some string');
result = gen_id(GEN_TABLEID, 0);
END
END^
SET TERM ; ^

Firebird stored procedure always returning zero

This is my stored procedure:
SET TERM ^ ;
CREATE PROCEDURE INSERT_ETYPE (
E_ID Integer,
E_NAME Varchar(20) CHARACTER SET NONE )
RETURNS (
NEW_ID Integer)
AS
declare variable addr varchar(20);
declare variable type smallint;
declare variable ord smallint;
declare variable cmd varchar(255);
declare variable answr varchar(255);
begin
insert into ETYPE
select * from ETYPE where ID=:e_id;
select max(ID) from ETYPE into :new_id;
update ETYPE set NAME = :e_name where ID = :new_id;
for
select ADDR,REGTYPE,ORD from ETYPEREGS
where ETYPE_ID=:e_id
into :addr,:type,:ord
do
begin
insert into ETYPEREGS
(ETYPE_ID,ADDR,REGTYPE,ORD)
values
(:new_id,:addr,:type,:ord);
end
for
select CMD,ANSWR,ORD,REGTYPE from ETYPESPECIAL
where ETYPE_ID=:e_id
into :cmd,:answr,:ord,:type
do
begin
insert into ETYPESPECIAL
(ETYPE_ID,CMD,ANSWR,ORD,REGTYPE)
values
(:new_id,:cmd,:answr,:ord,:type);
end
end^
SET TERM ; ^
This is my code in C++:
StoredProc_InsertEType->ParamByName("E_ID")->AsInteger = src_id;
StoredProc_InsertEType->ParamByName("E_NAME")->AsString = _name;
try
{
StoredProc_InsertEType->ExecProc();
new_id = StoredProc_InsertEType->ParamByName(L"NEW_ID")->AsInteger;
}
catch(EDBEngineError & e)
{
errors->Add(e.Message);
return false;
}
Variable new_id is always zero regardless of fact that table ETYPE is not empty. When I run command SELECT MAX(ID) FROM ETYPE from administration tool FlameRobin it returns correct number (~180). What should I do to obtain correct value of NEW_ID parameter?
you need to add
suspend;
in your sp
and query with
select * from your_sp
suspend explained
http://www.janus-software.com/fbmanual/manual.php?book=psql&topic=104
regards,

Resources