How to Execute Macro through Stored Procedure - stored-procedures

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.

Related

update a column inside a stored procedure

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 ...] ) ] ;

Dynamic Creation of External Tables in Synapse

I have a json string which is the result of Get Metadata activity in data factory in the following format: {"structure": [{"name": "Id","type": "String"},{"name": "IsDeleted","type": "Boolean"},{"name": "RowVersion","type": "Byte[]"}, {"name": "ModelId","type": "String"}]
This json is showing the schema of parquet file. I pass this json along with the parquet filename and uctnow() to a stored procedure to create a table of schema for that file with the following code
CREATE OR ALTER PROCEDURE [CreateExternalTables] (
#schema NVARCHAR (MAX), #tableName NVARCHAR(MAX), #ExecTime NVARCHAR(MAX)
) AS
BEGIN
IF OBJECT_ID('tempdb..#tables_to_create', 'U') IS NOT NULL
DROP TABLE #tables_to_create
CREATE TABLE #tables_to_create (
tableName NVARCHAR (MAX),
fieldOrder NVARCHAR (MAX),
fieldName NVARCHAR (MAX),
fieldType NVARCHAR (MAX),
translatedType NVARCHAR (MAX),
executeTime NVARCHAR (MAX)
)
BEGIN
WITH Fields (fieldOrder, fieldName, fieldType) AS (
SELECT
[key] AS fieldOrder,
JSON_VALUE([value], '$.name') AS fieldName,
JSON_VALUE([value], '$.type') AS fieldType
FROM
OPENJSON(#schema)
)
INSERT INTO
#tables_to_create(
tableName,
fieldOrder,
fieldName,
fieldType,
translatedType,
executeTime
)
SELECT
#tableName,
fieldOrder,
fieldName,
fieldType,
CASE
WHEN fieldType = 'Single' THEN 'real'
WHEN fieldType = 'Boolean' THEN 'bit'
WHEN fieldType = 'Double' THEN 'float'
WHEN fieldType = 'Int64' THEN 'bigint'
ELSE NULL
END AS translatedType,
#ExecTime
FROM
Fields
END
END;
The overall setup is like below:
But I receive the following error which I'm not sure why:
What I would like to do is to create this temo table in stored procedure in order to create external tables in a automatic way.
To be precise I'm following this link to do it:
create-external-dataset
Any help is highly appreciated.
UPDATE
After solving the first problem with #wBob 's help I follow the rest of the link to create the external tables with the following which I inserted into my stored procedure:
FROM
Fields
END
Declare #sqlCommand nvarchar(max);
Declare #folderPath nvarchar(max);
SET
#sqlCommand = 'IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].[' + #tableName + ']'') AND type in (N''U''))
CREATE EXTERNAL TABLE [dbo].[' + #tableName + '] ('
WHILE((SELECT COUNT(*) FROM #tables_to_create) > 0)
BEGIN
DECLARE #key int
SELECT
#key = MIN(fieldOrder)
FROM
#tables_to_create
WHERE
executeTime = #ExecTime
DECLARE #fieldName VARCHAR(50)
DECLARE #translatedType VARCHAR(50)
SELECT
#fieldName = fieldName,
#translatedType = translatedType
FROM
#tables_to_create
WHERE
fieldOrder = #key
AND executeTime = #ExecTime
SET
#sqlCommand = #sqlCommand + '
[' + #fieldName + '] [' + #translatedType + '] NULL'
DELETE FROM
#tables_to_create
WHERE
fieldOrder = #key
AND executeTime = #ExecTime
IF((SELECT COUNT(*) FROM #tables_to_create WHERE executeTime = #ExecTime) > 0)
SET
#sqlCommand = #sqlCommand + ', '
END
SET
#sqlCommand = #sqlCommand + '
)
WITH
(
LOCATION = ''/' + /main/json/ + ''',
DATA_SOURCE = DataLakeStaged,
FILE_FORMAT = StagedParquet
)'
EXEC(#sqlCommand)
END;
However I receive the following error:
As per the error message, queries are not supported in the conditions of WHILE statement in Azure Synapse Analytics. Dedicated SQL pools are MPP systems that have some slight differences from box-product SQL Server and Azure SQL DB and more generally, loops are a pattern that don't translate that well. You should consider creating a stored procedure that does not loop and leave any looping required to the For Each activity in Azure Data Factory (ADF) / Synapse Pipelines which can loop in parallel.
If you do require a loop, there are multiple examples of doing loops in dedicated SQL pools online, but there is a good example in the official documentation, reproduced here in the event the link moves:
-- First, create a temporary table containing a unique row number used to identify the individual statements:
CREATE TABLE #tbl
WITH
( DISTRIBUTION = ROUND_ROBIN
)
AS
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Sequence
, [name]
, 'UPDATE STATISTICS '+QUOTENAME([name]) AS sql_code
FROM sys.tables
;
-- Second, initialize the variables required to perform the loop:
DECLARE #nbr_statements INT = (SELECT COUNT(*) FROM #tbl)
, #i INT = 1
;
-- Now loop over statements executing them one at a time:
WHILE #i <= #nbr_statements
BEGIN
DECLARE #sql_code NVARCHAR(4000) = (SELECT sql_code FROM #tbl WHERE Sequence = #i);
EXEC sp_executesql #sql_code;
SET #i +=1;
END

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;

Execute immediate in user defined function - called in inner query

I am using a stored procedure to fetch records from an oracle database. This procedure returns paginated records building dynamic SQL query based on search inputs provided. Output 'STATUS' column is derived from user defined function 'GET_STATUS_FOR_ME'. Some derived columns are passed to this function based on this actual status of each record is calculated.
Everything works fine while not providing status as input search criteria. when status is provided it gives me the following error.
ORA-06535: statement string in EXECUTE IMMEDIATE is NULL or 0 length
ORA-06512: at "pkg_search", line 15
06535. 00000 - "statement string in %s is NULL or 0 length"
*Cause: The program attempted to use a dynamic statement string that
was either NULL or 0 length.
*Action: Check the program logic and ensure that the dynamic statement
string is properly initialized.
My user defined function is as below:
FUNCTION GET_STATUS_FOR_ME(
RECORDID IN NUMBER,
ASSIGNEDTO IN NUMBER,
LOCATIONID IN NUMBER,
TEMPUSERID IN NUMBER,
ACTUALSTATUS IN VARCHAR2)
RETURN VARCHAR2
AS
O_STATUS VARCHAR2(200 BYTE);
TEMP_QUERY VARCHAR2(200 BYTE);
I_COUNT NUMBER;
BEGIN
IF LOCATIONID IS NOT NULL AND TEMPUSERID IS NULL THEN
TEMP_QUERY := 'SELECT COUNT(*) FROM MY_TABLE WHERE COUNTRYIF = ' || TO_CHAR(LOCATIONID);
EXECUTE IMMEDIATE TEMP_QUERY INTO I_COUNT;
END IF;
. . . Other FUNCTION logic here. . .
RETURN O_STATUS;
END GET_STATUS_FOR_ME;
My procedure from which this function is being called is as below. This function is being called from inner query.
PROCEDURE SEARCH_RESULT_PROC(
I_LOGGEDINUSERID IN NUMBER,
I_CREATEDFROMDATE IN DATE,
I_CREATEDTODATE IN DATE,
I_STATUS IN VARCHAR2,
I_COUNTRYID IN NUMBER,
I_LANGUAGEID IN NUMBER,
I_OFFSET IN NUMBER,
I_LIMIT IN NUMBER,
I_ORDRBY IN VARCHAR2,
I_SORTBY IN VARCHAR2,
O_COUNT OUT NUMBER,
REF_CUS_RESULTS OUT SYS_REFCURSOR)
AS
PAG_END_ROW NUMBER;
STC_SQL_PART VARCHAR2(9999 BYTE);
DYNMC_SQL_CLAUSE_PART VARCHAR2(9999 BYTE);
BEGIN
PAG_END_ROW := I_OFFSET + I_LIMIT - 1;
STC_SQL_PART := 'select ID, REOCRDSTATUS,
(CASE
some logic here
END) LOCATIONID,
(CASE
some logic here
END) USERID from MY_TABLE MTABLE';
. . Other Logic TO build dynamic WHERE clause depending ON inputs provided. . .
IF I_DOCSTATUS IS NOT NULL THEN
DYNMC_SQL_CLAUSE_PART := DYNMC_SQL_CLAUSE_PART || ' AND UPPER(TEMPDATA.STATUS) = UPPER(''' || I_STATUS || ''')';
END IF;
FINAL_QUERY := 'SELECT ODATA.EID,
ODATA.TITLE,
ODATA.TYPE,
pkg_search.GET_STATUS_FOR_ME(ID,' || I_LOGGEDINUSERID || ',ODATA.LOCATIONID,ODATA.USERID,ODATA.REOCRDSTATUS) STATUS
FROM (SELECT ROWNUM RNUM , TEMP.* FROM ( ' || STC_SQL_PART || DYNMC_SQL_CLAUSE_PART || ' )TEMP WHERE ROWNUM <= ' || TO_CHAR(PAG_END_ROW) ||' ) ODATA WHERE ODATA.RNUM >= '|| TO_CHAR( I_OFFSET) ;
OPEN REF_CUS_RESULTS FOR FINAL_QUERY;
END SEARCH_RESULT_PROC;

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 ; ^

Resources