Retrieve particular column value using procedure in pl/sql - select

am writing procedure in pl/sql. when i run the procedure am getting error.Here i enclosed the procedure.
code
PROCEDURE get_CDR_rs_phone (CDR_recordset OUT SYS_REFCURSOR)AS
BEGIN
OPEN CDR_recordset FOR
SELECT zkv.CISCOCUIC_TBL.FLD_callingPartyNumber FROM zkv.CISCOCUIC_TBL;
END get_CDR_rs_phone;
/
getting error when i run this proc

Create your procedure as
CREATE OR REPLACE PROCEDURE get_cdr_rs_phone (
cdr_recordset OUT sys_refcursor
)
AS
BEGIN
OPEN cdr_recordset FOR
SELECT zkv.ciscocuic_tbl.fld_callingpartynumber
FROM zkv.ciscocuic_tbl;
END get_cdr_rs_phone;
/
and execute your procedure
variable r refcursor;
DECLARE
BEGIN
get_cdr_rs_phone (:r);
END;
/
print r
Update 1
If your procedure is doing only a select you could do this using a function which return sys_refcursor and the function can be executed from a sql statement.
Create function as
CREATE OR REPLACE FUNCTION get_cdr_rs_phone_func
RETURN sys_refcursor
AS
out_cursor sys_refcursor;
BEGIN
OPEN out_cursor FOR
SELECT zkv.ciscocuic_tbl.fld_callingpartynumber
FROM zkv.ciscocuic_tbl;
END get_cdr_rs_phone;
RETURN out_cursor;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
--raise error
WHEN OTHERS
THEN
--raise error
END get_cdr_rs_phone_func;
/
and call this function as
select get_cdr_rs_phone_func from dual;

Related

Postgres function with nested IF & ELSE statement error

I have this function where it looks up all the users and if any one does not exists do not create the function. What is wrong?
RETURNS event_trigger AS $$
DECLARE
audit_query TEXT;
r RECORD;
BEGIN
IF tg_tag IN ('CREATE TABLE', 'CREATE TABLE AS')
THEN
IF EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'test' or rolname = 'testa')
THEN
FOR r IN
SELECT * FROM pg_event_trigger_ddl_commands() AS ddl WHERE ddl.schema_name IN ('testb','testc','testd')
LOOP
INSERT INTO user_monitor.ddl_history (ddl_date, ddl_tag, object_name) VALUES (statement_timestamp(), tg_tag, r.object_identity);
END LOOP;
else
RAISE EXCEPTION 'Not all users found';
END IF;
END;
$$ LANGUAGE plpgsql
SQL Error [42601]: ERROR: syntax error at or near ";"
SQL Error [42601]: ERROR: missing "THEN" at end of SQL expression
Position: 286
An excerpt from the manual:
Event triggers are created using the command CREATE EVENT TRIGGER. In order to create an event trigger, you must first create a function with the special return type event_trigger.
This function need not (and may not) return a value; the return type serves merely as a signal that the function is to be invoked as an event trigger.
Emphasis on the second sentence.
You should probably replace your RETURN with RAISE EXCEPTION instead.
https://www.postgresql.org/docs/current/event-trigger-table-rewrite-example.html

Using nested loops in Redshift

I am trying to create a nested for loop within a Redshift procedure but getting following error; SQL Error [24000]: ERROR: opening multiple cursors from within the same client connection is not allowed.
Question: What is the best way to get around it?
Example code:
create or replace procedure test.nested_loop as $$
declare
row RECORD;
row2 RECORD;
begin
for row in
select
*
from
(
select
col_name
from
tbl_name1
)
loop
execute 'some code';
for row2 in
select
*
from
(
select
col_name2
from
tbl_name2
)
loop
execute 'some code';
end loop;
end loop;
return;
end;
$$ language plpgsql;
You need to create a single cursor with all the info you need. This can be done by cross joining your tables.
create or replace procedure test.nested_loop as $$
declare
row RECORD;
begin
for row in
select
*
from
(
select
tbl_name1.col_name, tbl_name2.col_name2
from tbl_name1
cross join tbl_name2
)
loop
execute 'some code that parses row.col_name and row.col_name2';
end loop;
return;
end;
$$ language plpgsql;
If the number of loops in this code is large you will want to address this in a different way. This process runs very slow as the number of rows being pulled from the cursor grows.

Declaring the table name in constant in Postgres Stored procedure

I have a sample stored procedure where in I have to use a table for multiple operations. I want to declare the table name as a constant and then re-use it wherever required. Below is the sample code which i wrote:
CREATE OR REPLACE FUNCTION get_data()
RETURNS void AS
$func$
DECLARE
table_name_a CONSTANT TEXT = asp.monitoring_bookmark_original;
cursor_file CURSOR FOR
select distinct filename,systemuid from table_name_a;
cursor_data CURSOR FOR
select * from table_name_a where filename = v_filename and systemuid=v_systemuid order by mindatetime, maxdatetime;
BEGIN
--open the file cursor
//logic goes here
END;
$func$
LANGUAGE plpgsql;
When I try to run this procedure I am getting error:
ERROR: missing FROM-clause entry for table "asp"
LINE 1: SELECT asp.monitoring_bookmark_original
What is wrong in this code? How do I correct this?
Well you can use dynamic SQL, but realize dynamic SQL often adds way more complexity. Good when really needed but should be avoided when possible. The following shows what would be needed for what you want to do. Is not having to type the table name for each SQL statement worth the additional trouble?
create or replace function get_data()
returns void as
$func$
declare
table_name_a constant text = 'asp.monitoring_bookmark_original';
file_cursor text = 'select distinct filename,systemuid from %i';
file_ref refcursor;
file_rec record;
data_cursor text =$stmt$select * from %i where filename = '%s' and systemuid= '%s' order by mindatetime, maxdatetime$stmt$;
data_ref refcursor;
data_rec record;
begin
--open the file cursor
open file_ref for execute format(file_cursor,table_name_a);
loop
fetch next from file_ref into file_rec;
exit when not found;
-- and extending from what the second query inplies
open data_ref for execute format(data_cursor,table_name_a,file_rec.filename,file_rec.systemid);
loop
fetch next from data_ref into data_rec;
exit when not found;
--//logic goes here
end loop;
end loop ;
end;
$func$
language plpgsql;

how to create event trigger for create table or select into

i want create event trigger for create table or select into,
eg:
when create table xxxx must table name bigen with 'temp'
my code
CREATE OR REPLACE FUNCTION create_table_func()
RETURNS event_trigger
AS
$$
DECLARE
V_TABLE name := TG_TABLE_NAME;
BEGIN
if V_TABLE !~ '^temp'
then
RAISE EXCEPTION 'must bigen with temp';
end if;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE EVENT TRIGGER create_table_1 ON ddl_command_start
WHEN TAG IN ('SELECT INTO')
EXECUTE PROCEDURE create_table_func();
but when execute
select * into test11 from test_bak
[Err] ERROR: column "tg_table_name" does not exist
this is my code ,it's meet my needs
code:
CREATE OR REPLACE FUNCTION trg_create_table_func()
RETURNS event_trigger
LANGUAGE plpgsql
AS $$
DECLARE
obj record;
BEGIN
FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands() WHERE command_tag in ('SELECT INTO','CREATE TABLE','CREATE TABLE AS')
LOOP
if obj.object_identity !~ 'public.temp_'
THEN
raise EXCEPTION 'The table name must begin with temp_';
end if;
END LOOP;
END;
$$;
CREATE EVENT TRIGGER trg_create_table ON ddl_command_end
WHEN TAG IN ('SELECT INTO','CREATE TABLE','CREATE TABLE AS')
EXECUTE PROCEDURE trg_create_table_func();
out recods
[Err] ERROR: The table name must begin with temp_
CONTEXT: PL/pgSQL function trg_create_table_func() line 10 at RAISE
it's cool ~
The special variable TG_TABLE_NAME is only supported in normal triggers, not in event triggers (there is not always an associated table!).
The documentation has a list of functions that can return context information in an event trigger.
You could use pg_event_trigger_ddl_commands() to get the information you need, but that only works in ddl_command_end event triggers. That should work for you; I don't see a reason why the trigger should not run at the end of the statement.

How to create a trigger function dynamically in pgsql?

I want to write a pgsql function to create trigger dynamically. For example, a trigger to count insertions in each table. I've tried EXECUTE like this:
CREATE FUNCTION trigen(tbl text) RETURNS void AS $$
BEGIN
EXECUTE format(
'CREATE FUNCTION %s_insertCnt() RETURNS TRIGGER AS $$
BEGIN
UPDATE insertions SET n = n + 1 WHERE tablename = %s;
END
$$ LANGUAGE plpgsql', tbl, quote_nullable(tbl));
EXECUTE format('CREATE TRIGGER %s_inCnt BEFORE INSERT ON %s
FOR EACH ROW EXECUTE PROCEDURE %s_insertCnt();', tbl, tbl, tbl);
END
$$ LANGUAGE plpgsql
But this approach doesn't work. A lot of syntax error occurred when I import this code. It seems that EXECUTE cannot execute a function creation.
What else can I do to create trigger functions dynamically?
The two $$ sections were getting confused. By using the $name$ syntax instead you can separate these.
Also the trigger was missing a RETURN.
CREATE OR REPLACE FUNCTION trigen(tbl text) RETURNS void AS $T1$
BEGIN
EXECUTE format(
'CREATE FUNCTION %s_insertCnt() RETURNS TRIGGER AS $T2$
BEGIN
UPDATE insertions SET n = n + 1 WHERE tablename = %s;
RETURN NEW;
END
$T2$ LANGUAGE plpgsql', tbl, quote_nullable(tbl));
EXECUTE format('CREATE TRIGGER %s_inCnt BEFORE INSERT ON %s
FOR EACH ROW EXECUTE PROCEDURE %s_insertCnt();', tbl, tbl, tbl);
END
$T1$ LANGUAGE plpgsql;