Cannot pass parameter inside stored procedure in redshift - sql

I have written the procedure which calls the parameter in the select query, but it's not working. When I print that parameter it's working fine, but with the select query, it's not working.
I have used Aginity workbench for redshift to execute the stored procedure.
CREATE or replace PROCEDURE get_tbl_name(IN tablename varchar, IN columnname VARCHAR, IN mindate varchar) AS $$
Declare
evalmindate varchar;
BEGIN
Raise info 'tablename = %, columnname = %, mindate = %', tablename,columnname,mindate;
if mindate is null then
select min(columnname) into evalmindate from tablename;
else
evalmindate=mindate;
end if;
END;
$$ LANGUAGE plpgsql;
Calling Proc:
call get_tbl_name('test_bq', 'date',NULL);
Output:
tablename = test_bq, columnname = date, mindate = <NULL>
Error Message
42601: syntax error at or near "$2"
From the output, we can able to see the parameter inside the procedure when I print, but I can't pass the parameter to the select query, it throwing an error. Kindly help me with this.

You can't use the variable as a column or table name directly in a stored procedure query. Instead you need to compose a query string and execute that.
Also the INTO var syntax needs to come first in a plain query and last in an EXECUTE.
You have:
select min(columnname) into evalmindate from tablename;
Try this:
EXECUTE 'select min('|| columnname ||') from '|| tablename ||';' INTO evalmindate;

Related

Procedure in Redshift Return "SELECT query has no destination for result data" Error

I keep getting the "SELECT query has no destination for result data" error upon calling this test procedure. What am I doing wrong? I did try adding the RETURN() command prior to SELECT statement but that didn't work either.
CREATE OR REPLACE PROCEDURE SchemaName.SP_Testing_Creating_Procedure (OUT ColumnName VARCHAR(9))
AS $$
BEGIN
SELECT TOP 10 ColumnName FROM SchemaName.TableName where ColumnName is not null;
END;
$$
LANGUAGE plpgsql;
CALL SchemaName.SP_Testing_Creating_Procedure();
As John mentioned you need to put the result into OUT column, examples of using IN, OUT and INOUT parameters you can find here
But if you need to return a few rows as a result, you have to use refcursor
as it's described here
CREATE OR REPLACE PROCEDURE SchemaName.SP_Testing_Creating_Procedure (INOUT result refcursor)
AS $$
BEGIN
OPEN result FOR
SELECT TOP 10 ColumnName
FROM SchemaName.TableName
WHERE ColumnName IS NOT null;
END;
$$
LANGUAGE plpgsql;
Then you can call the stored procedure in a transaction
BEGIN;
CALL logs.SP_Testing_Creating_Procedure('mycursor');
FETCH ALL FROM mycursor;
COMMIT;
another option is temp table which is also described in the above doc
Your procedure is running a SELECT command, but it is not doing anything with the results.
If your intention was to return a result set, you will need to put data in the OUT column.
See: Returning a result set - Amazon Redshift

dynamic sql selection in nested select

Let's say that I have a tables tasks, projects, and work_items, all of which have a column fields containing a json object of custom values.
Now lets say I want to write a function to query an arbitrary table for its field names.
CREATE OR REPLACE FUNCTION getFieldNames(varchar) RETURNS varchar[] AS
$BODY$
DECLARE
fieldNames varchar[];
BEGIN
fieldNames := ARRAY(SELECT DISTINCT fieldName FROM
(EXECUTE 'SELECT json_object_keys(fields) AS fieldName FROM '
|| quote_ident($1)
) AS derivedFields
);
RETURN fieldNames;
END
$BODY$
LANGUAGE 'plpgsql';
This however errors out with:
ERROR: syntax error at or near "'SELECT json_object_keys(fields) AS fieldName FROM'"
LINE 8: (EXECUTE 'SELECT json_object_keys(fields) AS fieldNa..
The Nested select itself is sound as I verified by replacing the execute with
(SELECT json_object_keys(fields) AS fieldName
FROM tasks
)
and receiving correct results.
What is wrong with my code?
The EXECUTE statement does not return a relation that you can use as a sub-query. Instead, if it returns anything at all, it populates a variable or a single row through the INTO clause. The latter obviously does not match your requirement so you are stuck with the first. A more elegant solution is to move the EXECUTE statement outwards:
EXECUTE
'SELECT array_agg(DISTINCT fields) FROM ' ||
'(SELECT json_object_keys(fields) AS fields FROM ' || quote_ident($1) || ') AS x'
INTO fieldNames;
The worst issue is wrong position of EXECUTE statement. It is a PLpgSQL statement and then it cannot be placed in any SQL expression.

error of running a stored proceudre in IBM netezza SQL database

I need to create a stored procedure in IBM netezza SQL database from IBM Aginity workbench.
This is my SQL code to create the SP:
CREATE OR REPLACE PROCEDURE "SP_drop_a_table_if_exists"(varchar(128))
RETURNS boolean
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
declare
oname alias for $1;
o record;
begin
select otype into o
from (
select 'TABLE' otype from _v_table where tablename = upper(oname)
union all
select 'VIEW' otype from _v_view where viewname = upper(oname)
) x;
if found then
execute immediate 'DROP '||o.otype||' '||oname;
end if;
end;
END_PROC;
I created successfully.
But, when I ran it,
CALL SP_drop_a_table_if_exists('test_a_table':: varchar(128))
I got error:
ERROR[42S02] error: function 'sp_drop_a_table_if_exists(varchar)' does not exists
unable to identify a function that satisdy the given argument types
you may need to add explicit typecasts
Any help would be appreciated !
You created your stored procedure with mixed case inside of double quotes...
CREATE OR REPLACE PROCEDURE "SP_drop_a_table_if_exists"(varchar(128))
...but when you call the stored procedure you don't use double quotes, so the name is being converted all upper case.
CALL SP_drop_a_table_if_exists('test_a_table':: varchar(128))
Try this instead:
CALL "SP_drop_a_table_if_exists"('test_a_table':: varchar(128))
I should also mention that more recent versions of NPS support this syntax for the DROP TABLE command:
DROP TABLE TABLENAME IF EXISTS;

DB2 - function to return max value from specified column

I'm new to DB2 PL/SQL and ran into some trouble, as there is not much community resources except for the official documentation which doesn't answer to all my questions.
I'm doing some data migration, and need a function that would return a max value from a specified column, from a specified table. In the last 2 hours I've come up with two approaches, but none of these works - due to my lack of knowledge of DB2 PL/SQL.
First one is preparing a query and executing it, but I can't execute a select query into a variable. Here's the code that doesn't execute:
CREATE OR REPLACE FUNCTION getMaxColValue (schemaName VARCHAR(30),
tableName VARCHAR(30), columnName VARCHAR(30))
-- function used to get max ID of a column during data migration
RETURNS INTEGER
LANGUAGE SQL
BEGIN
DECLARE query VARCHAR(1000);
DECLARE maxColValue INT;
DECLARE stmt STATEMENT;
SET query = 'select max(' || columnName || ') from ' || schemaName || '.' || tableName || '';
PREPARE stmt FROM query;
EXECUTE query INTO maxColValue;
RETURN maxColValue;
END
Error returned:
Lookup Error - DB2 Database Error: ERROR [07003] [IBM][DB2/AIX64] SQL0518N The statement named in the EXECUTE statement is not in a prepared state or is a SELECT or VALUES statement.
I've also tried something like this, returning scalar SQL value:
CREATE FUNCTION getMaxColValue_2 (schemaName VARCHAR(30), tableName VARCHAR(30), columnName VARCHAR(30))
RETURNS INT
LANGUAGE SQL
READS SQL DATA
NO EXTERNAL ACTION
DETERMINISTIC
RETURN
SELECT max(columnName)
FROM schemaName.tableName;
Error returned:
Lookup Error - DB2 Database Error: ERROR [42704] [IBM][DB2/AIX64] SQL0204N "SCHEMANAME.TABLENAME" is an undefined name.
but I guess it's harder to pass schemaname and tablename as variables here. I'll be gateful for any help. Window function is not much of an option, as I need to use this function in migration procedures and not simple select statements.
There are some syntax errors, but what's worse there are probably some logical errors due to my lack of knowledge of PL/SQL.
Cheers,
Jony
You cannot EXECUTE a SELECT statement, which is exactly what the error message is telling you.
Instead, you should declare a cursor, open it, then fetch the result into your variable:
CREATE OR REPLACE FUNCTION getMaxColValue (schemaName VARCHAR(30),
tableName VARCHAR(30), columnName VARCHAR(30))
RETURNS INTEGER
LANGUAGE SQL
not deterministic
reads sql data
begin
declare l_max int;
declare c_cur cursor for l_stmt;
prepare l_stmt from 'select max(' || columnName || ') from ' || rtrim(schemaName) ||
'.' || tableName;
open c_cur;
fetch c_cur into l_max;
close c_cur;
return l_max;
end

Executing SQL Function using toad

I am very new to DB. I am java developer and nothing to do with SQL Functions.
But now I am in a situation where I need to check whether an sql function is getting executed properly on db or not
CREATE OR REPLACE FUNCTION RATELIMIT_OWN.Get_Logs ( p_yyyymm VARCHAR2, p_numec NUMBER )
RETURN LOG_RECORD_TABLE PIPELINED IS
TYPE ref0 IS REF CURSOR;
cur0 ref0;
out_rec LOG_RECORD := log_record(NULL,NULL,NULL);
BEGIN
OPEN cur0 FOR
'SELECT eventid, errormsg, create_date from logs partition (LOGS_P' || p_yyyymm || ') where numec=:1'
USING p_numec;
LOOP
FETCH cur0 INTO out_rec.eventid, out_rec.msg, out_rec.create_date;
EXIT WHEN cur0%NOTFOUND;
PIPE ROW(out_rec);
END LOOP;
CLOSE cur0;
RETURN;
END Get_Logs;
/
How to execute this sql function in toad. I want to see the results like normal Select query output
To check a table valued function please try:
select * FROM table(RATELIMIT_OWN.Get_Logs('a', 1));
FOE EXECUTING THE FUNCTION
SELECT RATELIMIT_OWN.Get_Logs(....,...) FROM DUAL ;
AND
ORA-00904: MEAN COLUMN NAME IS NOT VALID PLSS CHECK THE COLUMN NAME
Try:
select RATELIMIT_OWN.Get_Logs(...) from dual;