how to store value from one procedure to another in PostgreSQL - postgresql

I have created procedure called UTILITY_SERVICES_SP_DELETE_SCHPAY that procedure is used in sp_del_benmast procedure.
i neead to store called procedure value into P_SUC_FLAG,P_ERROR variable.
Is this possible to do.
or should i convert UTILITY_SERVICES_SP_DELETE_SCHPAY procedure into function
SELECT *
FROM UTILITY_SERVICES_SP_DELETE_SCHPAY(P_ENTITY_CODE, P_CUST_CODE, IDY.SRV_REF_NUM, P_SUC_FLAG, P_ERROR)
INTO STRICT P_SUC_FLAG,P_ERROR;

Related

Is it possible to create a Stored Procedure for Select statements?

If no, please suggest efficient alternatives if possible, I'll edit my question and include the source code if requested
If you want to encapsulate a SQL statement into something "callable", then put it into a function
create function get_data(p_some_value int)
returns table (some_number int, some_date date, some_value text)
as
$$
select c1, c2, c3
from some_table
where x1 = p_some_value;
$$
language sql
stable;
A stored procedure is a prepared SQL code that you can save, so the code can be reused over and over again.
Stored Procedure Syntax:
CREATE PROCEDURE procedure_name
AS
sql_statement
GO;
If you have an SQL query that you write over and over again, save it as a stored procedure, and then just call it to execute it.
You can also pass parameters to a stored procedure so that the stored procedure can act based on the parameter value(s) that is passed.

What is the syntax to define a Postgres procedure within an another stored procedure?

I am migrating my Oracle DB to Postgres. But there is an Oracle procedure like this:
create or replace
PROCEDURE TOP_PROCEDURE
(...)
IS
variable NUMBER;
PROCEDURE nested_procedure (...)
IS
BEGIN
NULL;
END;
PROCEDURE another_nested_procedure (...)
IS
BEGIN
NULL;
END;
BEGIN
NULL;
END;
PG doesn't support this syntax. I try to convert these nested procedure to global procedure.
But there are too many nested procedures waiting me to convert.
I wonder if PG supports nested procedure? And what's the syntax?
Thanks!
PostgreSQL doesn't support this.
I recommend creating a special schema that contains all auxiliary functions, then they won't clutter the schema that contains the main function.

How to return result set from PostgreSQL stored procedure?

PostgreSQL supports stored procedure (not function) since version 11. I created a stored procedure like this:
CREATE OR REPLACE PROCEDURE get_user_list ()
LANGUAGE SQL
SECURITY DEFINER
AS $$
SELECT "id",
"username",
"display_name"
FROM "user"
ORDER BY "created_at" ASC;
$$;
But when I am trying to execute this stored procedure, it does not return any data:
postgres=# CALL get_user_list();
CALL
postgres=# SELECT * FROM get_user_list();
ERROR: get_user_list() is a procedure
LINE 1: SELECT * FROM get_user_list();
^
HINT: To call a procedure, use CALL.
So the question is, how can a stored procedure returns its result set in PostgreSQL 11+?
Following the docs on Postgres 11 (bold emphasis mine):
A procedure does not have a return value. A procedure can therefore end without a RETURN statement. If a RETURN statement is desired to exit the code early, then NULL must be returned. Returning any other value will result in an error.
You could mark your parameters as output though, so that they would behave like variables.
On a side note there's normally a distinction within other DBMS that functions can only call SELECT statements and should not modify data while procedures should be handling the data manipulation and data definition languages (DML, DDL). This concludes (in my opinion) that creating a procedure to simply perform a stable (*) select statement is not the desired technique.
(*) Read more on function volatility here.
In case if you have one select in procedure to get result set you can create view like this:
CREATE OR REPLACE VIEW as get_user_list
SELECT "id",
"username",
"display_name"
FROM "user"
ORDER BY "created_at" ASC;
and then select * from get_user_list to get result set.

PostgreSQL Trigger Error : control reached end of trigger procedure without RETURN

I am trying to create a trigger on a column of my table like this in Postgresql 9.5:
CREATE OR REPLACE FUNCTION app.combo_min_stock()
RETURNS TRIGGER AS
$combo_sync$
DECLARE combo_product_ids INTEGER[] := array(SELECT combo_product_map.combo_productid FROM app.combo_product_map WHERE combo_product_map.productid=NEW.productid);
DECLARE comboid INTEGER;
BEGIN
-- UPDATE MINIMUM STOCK FOR COMBO SKUS --
FOREACH comboid IN ARRAY combo_product_ids
LOOP
UPDATE app.inventory SET
good_stock = combo_data.min_good_stock,
bad_stock = combo_data.min_bad_stock,
to_be_updated = true
FROM
(SELECT
product.productid,
MIN(inventory.good_stock) as min_good_stock,
MIN(inventory.bad_stock) as min_bad_stock
FROM
app.product,
app.inventory,
app.combo_product_map
WHERE
product.is_combo=true AND
product.productid=comboid AND
product.productid=combo_product_map.combo_productid AND
combo_product_map.productid=inventory.productid
GROUP BY
product.productid) AS combo_data
WHERE
combo_data.productid=inventory.productid;
END LOOP;
END;
$combo_sync$
LANGUAGE plpgsql;
ALTER FUNCTION app.combo_min_stock()
OWNER TO postgres;
CREATE TRIGGER combo_sync
AFTER UPDATE OF good_stock
ON app.inventory
FOR EACH ROW
EXECUTE PROCEDURE app.combo_min_stock();
When I try to edit a value for good_stock column in my inventory table, it is throwing me this error:
An error has occurred:
ERROR: control reached end of trigger procedure without RETURN
CONTEXT: PL/pgSQL function app.combo_min_stock()
What is wrong with this query?
Try using this:
END LOOP;
RETURN NULL;
According to CREATE TRIGGER docs
function_name
A user-supplied function that is declared as taking no arguments and
returning type trigger, which is executed when the trigger fires.
In the syntax of CREATE TRIGGER, the keywords FUNCTION and
PROCEDURE are equivalent, but the referenced function must in any
case be a function, not a procedure. The use of the keyword
PROCEDURE here is historical and deprecated.
What is trigger function?
Function which returns a trigger. ex:
CREATE FUNCTION do_something() RETURNS trigger
Important bit is trigger function should be function not a procedure
Difference between Procedures and Functions according to docs
A procedure is a database object similar to a function. The key
differences are:
Procedures are defined with the CREATE PROCEDURE command, not CREATE
FUNCTION.
Procedures do not return a function value; hence CREATE PROCEDURE
lacks a RETURNS clause. However, procedures can instead return data to
their callers via output parameters.
While a function is called as part of a query or DML command, a
procedure is called in isolation using the CALL command.
A procedure can commit or roll back transactions during its execution
(then automatically beginning a new transaction), so long as the
invoking CALL command is not part of an explicit transaction block. A
function cannot do that.
Certain function attributes, such as strictness, don't apply to
procedures. Those attributes control how the function is used in a
query, which isn't relevant to procedures.
Simply put functions should have a return statement
So each and every trigger function need to have a return statement. Some possible return statements for trigger functions.
RETURN NULL;
RETURN OLD;
RETURN NEW;

How to execute procedure returning resultset in Firebird

I have the following table
create table LIST_PIPE_TABLE
(
ID INT,
ITEM VARCHAR(4000),
IS_FOLDER VARCHAR(10)
)
with 3 rows of data
insert into LIST_PIPE_TABLE values(1,'Victorias Secret','true')
insert into LIST_PIPE_TABLE values(2,'Porsche','true')
insert into LIST_PIPE_TABLE values(3,'Babbolat','false')
And a stored procedure that should return resultset
CREATE or alter PROCEDURE LIST_PIPE
RETURNS
( col1 varchar(4000),
col2 varchar(10)
)
AS
begin
FOR SELECT ITEM AS ITEM
,IS_FOLDER AS IS_FOLDER
FROM LIST_PIPE_TABLE
into :col1, :col2
do begin
suspend;
end
end
When I try to execute it with the following statement
execute procedure LIST_PIPE
the only one top row is returned
COL1 COL2
Victorias Secret true
Please advise what is wrong about it. How should I execute it to see all 3 rows it is designed to return?
When you have suspend in stored procedure, it is called "selectable stored sprocedure", and as the name says you select from it, so:
select * from LIST_PIPE
As ain already answered, you need to use SELECT * FROM <your procedure> for a selectable procedure (that is: it contains a SUSPEND).
The Interbase 6 Embedded SQL Guide (see under InterBase 6.0 Manuals) says:
There are two types of procedures that can be called from an application:
Select procedures that an application can use in place of a table or view in a SELECT statement. A select procedure must return one or more values, or an error results.
Executable procedures that an application can call directly, with the EXECUTE PROCEDURE statement. An executable procedure may or may not return values to the calling program.
Both kinds of procedures are defined with CREATE PROCEDURE and have the same syntax. The difference is in how the procedure is written and how it is intended to be used. Select procedures always return zero or more rows, so that to the calling program they appear as a table or view. Executable procedures are simply routines invoked by the calling program that can return only a single set of values.
In fact, a single procedure conceivably can be used as a select procedure or an executable procedure, but this is not recommended. In general a procedure is written specifically to be used in a SELECT statement (a select procedure) or to be used in an EXECUTE PROCEDURE statement (an executable procedure).
On a protocol level, an EXECUTE PROCEDURE statement will always produce a single row of results (which might be empty), where as a SELECT * FROM <procedure> will behave the same as a select from a table or view. This means that if a selectable procedure is called with EXECUTE PROCEDURE, that Firebird itself will fetch only one row from the stored procedure, and then end execution of the procedure.
It is unfortunate that it is possible to use EXECUTE PROCEDURE with a selectable procedure. The Interbase 6 Language Reference on SUSPEND explicitly mentions "SUSPEND should not be used in an executable procedure." (the phrasing is weird, because the presence of SUSPEND is what makes it selectable, though here they mean calling it with EXECUTE PROCEDURE is not advisable).