Update query running slow in stored procedure - sql

I have created a query to update the records in database based on certain condition. My query is something like below:
update table1
set value ='some value'
where id in ( /*inner query based on joins*/)
When I execute this query directly in dbeaver tool, it completes in about 20 sec.
There are about 11million records in the database.
But when I run the same query in stored procedure, it takes about 40 minutes.
Below is how my stored procedure is created:
CREATE OR REPLACE PROCEDURE update_query_procedure(input_value varchar)
LANGUAGE 'plpgsql'
AS $$
DECLARE
update_query varchar := ' update table1 '
' set "value" = ''some value'''
' where id in ('
' /* inner query */
' )';
BEGIN
update_query = replace(update_query, 'replace', input_value);
EXECUTE update_query;
END;
$$;
Why is there a difference in execution time when the query is executed directly and from the stored procedure? How can I debug where the issue is?

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

Cannot pass parameter inside stored procedure in redshift

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;

I want to get count for rows in cursor in DB2

CREATE OR REPLACE PROCEDURE USP_TEST_ROW_COUNT(
OUT vROW_COUNT BIGINT
)
RESULT SETS 1
MODIFIES SQL DATA
LANGUAGE SQL
P1: BEGIN ATOMIC
BEGIN
DECLARE C1 CURSOR WITH RETURN FOR
SELECT * FROM TABLE_NAME;
OPEN C1;
SET vROW_COUNT = CURSOR_ROWCOUNT(C1);
END;
END P1
Above is my code but it is showing Below Error
DB2 SQL error: SQLCODE: -206, SQLSTATE: 42703, SQLERRMC: C1
Message: "C1" is not valid in the context where it is used.
Line: 12
Please Help.
You may insert the results into some DGTT if you want to return all rows in the result set and return the number of output rows simultaneously:
CREATE OR REPLACE PROCEDURE USP_TEST_ROW_COUNT(OUT vROW_COUNT BIGINT)
RESULT SETS 1
MODIFIES SQL DATA
BEGIN ATOMIC
DECLARE v_stab VARCHAR(100) DEFAULT 'SESSION.USP_TEST_ROW_COUNT';
DECLARE v_stmt VARCHAR(100) DEFAULT 'SELECT * FROM TABLE_NAME';
DECLARE C1 CURSOR WITH RETURN FOR S1;
EXECUTE IMMEDIATE
'DECLARE GLOBAL TEMPORARY TABLE '||v_stab||' AS ('
||v_stmt
||' ) DEFINITION ONLY WITH REPLACE ON COMMIT PRESERVE ROWS NOT LOGGED';
EXECUTE IMMEDIATE 'INSERT INTO '||v_stab||' '||v_stmt;
GET DIAGNOSTICS vROW_COUNT=ROW_COUNT;
PREPARE S1 FROM 'SELECT * FROM '||v_stab;
OPEN C1;
END#
CURSOR_ROWCOUNT can only return the number of rows fetched (by the caller of the stored procedure). This is different from the number of rows in the result set. So if your syntax was accepted the value would be zero initially as nothing as yet been fetched.
You can see an example here, which shows the cursor variable, the cursor being opened and fetched, and the resulting value returned by CURSOR_ROWCOUNT.
To find the number of rows in the result-set either consume the cursor (fetch until no more rows), or do a second query that counts the rows in the same unit of work, or append the count to each row and fetch only 1 row.

Teradata stored procedure with dynamic parameters called from R script

I need to extract some data from Teradata to process in R. I have around 84 Dep/sec keys with most of them having a different time span so my thought was to create a stored procedure in Teradata that will accept the Dep, Sec and Dates as parameters. I could then loop over the list in R calling the SP each time to create my data set.
The SP I have created to test this idea is a very simple one but I can't get it to work.
CREATE PROCEDURE procTest4 (IntN integer)
BEGIN
CALL DBC.SysExecSQL('SELECT top' || IntN || '*
from TableName');
END;
Teradata does create the SP but I don't know how to execute it and pass the paramters to it. When I try:
Call procText4(10)
I get the following error:
5568: SQL statement is not supported within a stored procedure.
The only other option for me is to create the SQL string in R and then run it from there but there is multiple passes of SQL which create volatile tables and the RODBC package doesn't seem to like them, plus it's a very messy way of doing it.
Any help is much appreciated.
The syntax for returning a result set from a Stored Procedure using Dynamic SQL is a bit complex:
CREATE PROCEDURE procTest4 (IntN INTEGER)
DYNAMIC RESULT SETS 1
BEGIN
DECLARE SqlStr VARCHAR(1000);
DECLARE rslt CURSOR WITH RETURN ONLY FOR stmt;
SET SQLStr = 'SELECT top ' || IntN || ' * from TableName';
PREPARE stmt FROM SqlStr;
OPEN rslt;
END;
But you should double check if you can rewrite those loops...

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