Using script variables in sql-do session not works? - postgresql

It is not a psql terminal, I can't use \set myvariable value as suggested here, and can't use ugly set+current_setting() as here ... I am using Pg9+ (9.5), so I think I can use sql-do as this in answer... But not working.
DO $$
DECLARE foo int := bar('etc');
BEGIN
SELECT run_somthing(foo,1);
SELECT run_somthing(foo,2);
END
$$;
ERROR-1: "query has no destination for the resulting data HINT: If you want to discard the results of a SELECT, use PERFORM."
ERROR-2: (after add PERFORM) "ERROR: syntax error at or near "SELECT"".
NOTE:
Also sintax error when using function workaround
CREATE or replace FUNCTION doThis() RETURNS int AS $$
DECLARE
foo int := bar('etc');
BEGIN
SELECT run_somthing(foo,1); -- bug also with PERFORM clause
SELECT run_somthing(foo,2);
RETURN 1;
END;
$$ LANGUAGE plpgsql;
SELECT doThis();

Related

How to add value in enum in plpgsql function

So I have some simple function that should add value to an existing enum "profession" but instead of working it shows error
CREATE FUNCTION add_prof(p text) RETURNS VOID AS $$
BEGIN
ALTER TYPE profession ADD VALUE p;
RETURN;
END;
$$ LANGUAGE plpgsql;
The error is "[42601] syntax error". Btw, DataGrip shows that "string or IF expected but p."
Changing p to ' ' of course works fine but that's not what I need.
ALTER command is DDL command, and DDL commands doesn't allow an parametrization (they has not an execution plan). You need to use dynamic SQL:
CREATE FUNCTION add_prof(p text)
RETURNS VOID AS $$
BEGIN
EXECUTE format('ALTER TYPE profession ADD VALUE %L', p);
RETURN;
END;
$$ LANGUAGE plpgsql;

How to declare a variable in postgres script?

I am fairly new to Postgres and I cannot believe how difficult I am finding just to declare a variable. I did come across other SO posts, but none of them helped in my situation. All I want is to write the a script like below in postgres:
declare #age int = 10;
select * from person p where p.age > #age;
Based on the SO post here, I tried:
DO
$$
DECLARE
overTheAgeOf int := 15;
BEGIN
select *
from person
where age > overTheAgeOf;
END
$$;
This gives me error: [42601] ERROR: query has no destination for result data
Then I tried returning the result of the script:
return (select *
from person
where age > overTheAgeOf);
That gave me another error: ERROR: RETURN cannot have a parameter in function returning void
How do declare a variable and use it in script(s) that follows?
You are confused on several levels.
There is the query language SQL, and there is the procedural language PL/pgSQL. The only connection is that
you can run SQL statements from PL/pgSQL code
you can have PL/pgSQL code in the body of the SQL statements DO and CREATE FUNCTION/PROCEDURE.
There are variables in PL/pgSQL, which are defined in the DECLARE section, but there are no variables in SQL.
DO statements cannot return any values.
If you want to use PL/pgSQL variables, and you want to return values, you'll have to use a function. An example:
CREATE FUNCTION getpersons() RETURNS SETOF person
LANGUAGE plpgsql AS
$$DECLARE
overTheAgeOf int := 15;
BEGIN
RETURN QUERY
SELECT *
FROM person
WHERE age > overTheAgeOf;
END;$$;
SELECT getpersons();
There is the alternative of using variables on the client. With the psql client, you could use:
\set overTheAgeOf 15
SELECT *
FROM person
WHERE age > :overTheAgeOf;
The good structure is like this :
DO
LANGUAGE plpgsql $$
DECLARE
variable int := 0;
BEGIN
-- your code
raise notice '%', variable::varchar;
END;
$$;

How to concat two string in postgresql function?

I want a function which will return concated string. I am getting following error after execute this function in postgresql.
CREATE OR REPLACE FUNCTION getTableName ()
RETURNS text AS $$
DECLARE
state_short_name text;
BEGIN
state_short_name := (select lower(state_short_name) from mst_state where state_code in (SELECT substr(entity_code,1,2) FROM shg_detail_share WHERE entity_code = '3420006002001'))
RETURN (CONCAT(state_short_name, '_shg_detail'));
END;
$$ LANGUAGE plpgsql
I expect the output like 'jh_shg_detail' but I am getting error like this
ERROR: syntax error at or near "("
LINE 9: RETURN (CONCAT(state_short_name, '_shg_detail'));
You should use a select into in PL/pgSQL. And to avoid a name clash, don't name variables the same as columns:
CREATE OR REPLACE FUNCTION gettablename()
RETURNS text AS $$
DECLARE
l_state_short_name text;
BEGIN
select lower(state_short_name)
into l_state_short_name
from mst_state
where state_code in (SELECT substr(entity_code,1,2)
FROM shg_detail_share
WHERE entity_code = '3420006002001'));
RETURN CONCAT(state_short_name, '_shg_detail');
END;
$$ LANGUAGE plpgsql;
But you don't need PL/pgSQL for a simple SQL query like that. Your sub-query isn't really necessary as well. You can simplify that to where state_code = '34'
CREATE OR REPLACE FUNCTION gettablename()
RETURNS text
AS $$
select concat(lower(state_short_name), '_shg_detail')
from mst_state
where state_code = '34';
$$
LANGUAGE sql;
Your problem is a missing semicolon at the line with the assignment statement :=.
This makes the line that starts with RETURN (CONCAT a continuation line of the statement, and so you get the syntax error reported in that line.

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;

PostgreSQL - not a known variable in procedure

I'm having trouble with writing a procedure in PostgreSQL. I can create the procedure, yet when i try to execute i get an error.The error i get
ERROR: "v_all_atts" is not a known variable
the query is:
CREATE OR REPLACE FUNCTION rebuild_views_with_extra_atts()
RETURNS VOID AS $$
DECLARE
v_all_atts varchar(4000);
BEGIN
CREATE OR REPLACE FUNCTION add_column(p_table text, p_column text,p_category text) RETURNS VOID AS $nothing$
declare
v_column_exists bigint := false ;
BEGIN
SELECT
string_agg( CASE WHEN owner='alarm' THEN 'ai' WHEN owner='fault' THEN 'fi'
END ||'.'||lower(alias) , ', ' ORDER BY owner, alias) AS string
INTO STRICT
v_all_atts
FROM
extra_attribute_cfg
WHERE
owner NOT LIKE 'virtual' and enable = true and v_column_exists = true;
IF LENGTH(v_all_atts) is not null THEN
v_all_atts := ', '||v_all_atts;
END IF;
v_view:= q'#
CREATE OR REPLACE VIEW alarm_view AS
SELECT
fi.fault_id, ai.alarm_id,
#'||v_all_atts||q'#
FROM
alarm ai
INNER JOIN fault fi
ON fi.fault_id = ai.fault_id
#';
EXECUTE v_view;
END;
$nothing$ language plpgsql;
end;
$$ LANGUAGE plpgsql;
I have taken a long look at Postgres documentation and cannot find what is wrong and didn't find any answer to this specific situation
Your rebuild_views_with_extra_atts() function is creating the add_column() function.
add_column() uses the v_all_atts variable, but it doesn't exist in that function, it exists only in the rebuild_views_with_extra_atts() function.
To resolve this, it really depends on what you're trying to do. If that variable should exist in the add_column() function, then declare it in there. If you're trying to use the value of v_all_atts when creating add_column() (e.g. so that the content of the function's body is dependent on the value of that variable), then you really need to use dynamic sql to generate a TEXT version of the CREATE OR REPLACE ... code, then EXECUTE it.