I have PostgreSQL v12 and this code works fine for me in this version. I have no idea if this is a version issue or not but I want to use POSTGRESQL v9.4
----------------------- Function Start v1.0 ------------------------------
drop function if exists aa_Dev.VDN();
CREATE OR REPLACE FUNCTION aa_dev.VDN()
RETURNS VOID AS
$$
declare
tempp json;
begin
DROP TABLE IF EXISTS aa_dev.sdg_vdn;
CREATE TABLE IF NOT EXISTS aa_dev.sdg_vdn (
VDN INT,
skills INT[]
);
tempp := (select VDN_group from aa_dev.sdg_metadata);
insert into aa_dev.sdg_vdn (vdn, skills)
select (jsonb_populate_record(null::aa_dev.sdg_vdn, to_jsonb(t))).*
from jsonb_each(tempp::jsonb) as t(vdn, skills);
end
$$
LANGUAGE plpgsql;
----------------- Function Ends ----------------------
select * from aa_dev.VDN();
select * from aa_dev.sdg_vdn;
So the error is
SQL Error [42883]: ERROR: function to_jsonb(text, jsonb) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Where: PL/pgSQL function aa_dev.vdn() line 17 at SQL statement
How can I eliminate this error and run the function in postgresql 9.4. I have a restriction with this version.
There is some support to jsonb in version 9.4. https://www.postgresql.org/docs/9.4/functions-json.html
You can instead of to_jsonb(t) use to_json(t)::jsonb
Related
I am new working postgresql and pgadmin4.I write a very simple query.
I have a table called PgFinalLocationsTable on public schema.In my table there are a few filed.One of these filed is UserName .I want to declare a variable and finally do select on my table according this variable like below:
DO $$
DECLARE myvar text default 'sa';
BEGIN
select * from public."PgFinalLocationsTable" where "UserName" = myvar;
END $$;
But why i got these message:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function inline_code_block line 4 at SQL statement
SQL state: 42601
It is a simple query!!!
After googling and see post on stack i have changed my query like this:
CREATE OR REPLACE FUNCTION fun(text myvar) RETURNS text AS $$
--DECLARE myvar text;
BEGIN
select * from public."PgFinalLocationsTable" where "UserName" = myvar;
END;
$$ language plpgsql;
select fun('sa');
I want to return all my fields and i do not want to use plpgsql.I want to use PostgreSQL. In any case i got this error:
ERROR: type myvar does not exist
SQL state: 42704
What is the problem on my first query and second query?Should i have make a function for select query when i want to pass a variable?
I do all stuff because i want to create this sql query:
"IF (NOT EXISTS(SELECT 1 FROM [dbo].[{0}] WHERE [UserId] = #UserId And [DeviceId] = #DeviceId)) " +
"BEGIN " +
"INSERT INTO [dbo].[{0}]([Id], [Location], [Timestamp], [UserId], [DeviceId], [AllowDomains], [Topic], [UserName], [FirstName], [LastName], [JobLocationName], [LocationId], [AppVersion], [AppName]) " +
"VALUES(#Id, GEOGRAPHY::Point(#X, #Y, 4326), #Timestamp, #UserId, #DeviceId, #AllowDomains, #Topic, #UserName, #FirstName, #LastName, #JobLocationName, #LocationId, #AppVersion, #AppName) " +
"END "
You don't understand to DO command well. DO command is anonymous function without declaration, and because it has not declared an output, then is not possible any other result than debug stream.
so your first example has not sense in PostgreSQL. Result of unbind queries in MSSQL is returned as result of MS SQL procedure. Nothing similar is possible in PostgreSQL. PostgreSQL knows only functions, that can returns scalar value, composite value or relation (only one). When you are coming from MS SQL, the best what you can, try to forgot almost all knowleadge from MS SQL.
ERROR: type myvar does not exist
SQL state: 42704
This bug is clean - you switch variable name and type name - really type myvar doesn't exist.
Some function that returns table can looks like:
CREATE OR REPLACE FUNCTION fx1(myvar text)
RETURNS SETOF public."PgFinalLocationsTable" AS $$
BEGIN
RETURN QUERY SELECT * FROM public."PgFinalLocationsTable" WHERE "UserName" = myvar;
END;
$$ LANGUAGE plpgsql;
or you can use a SQL language only
CREATE OR REPLACE FUNCTION fx1(myvar text)
RETURNS SETOF public."PgFinalLocationsTable" AS $$
SELECT * FROM public."PgFinalLocationsTable" WHERE "UserName" = $1;
$$ LANGUAGE sql;
Because PostgreSQL doesn't support unbind queries, then doesn't allow it. You should to use RETURN QUERY command - in PLpgSQL language.
Because programming with stored procedures is really different between PostgreSQL and MSSQL (MSSQL is not similar to any other), please, try to read documentation - it is not bad https://www.postgresql.org/docs/current/static/plpgsql.html
Your function can looks in Postgres like (I don't know used types)
CREATE OR REPLACE FUNCTION fx("_UserId" int,
"_DeviceId" int,
"_X" int,
"_Y" int,
...
BEGIN
IF NOT EXISTS(SELECT * FROM /* I don't know what [{0}] means */
WHERE "UserId" = "_UserId" AND "DeviceId" = "_DeviceId")
THEN
INSERT INTO ..
END IF;
END;
$$ LANGUAGE plpgsql;
Probably your fragment can be solved without procedural extension by INSERT INTO ON CONFLICT DO NOTHING command https://www.postgresql.org/docs/current/static/sql-insert.html - what is better.
Note - using case sensitive identifiers is short way to hell.
I am trying to write a function to get the list of objects in schema from Redshift. I have created a dblink from RDS PostgreSQL to Redshift. The query is working just fine when invoked individually, but not working when written inside a function with arguments. I want to pass multiple arguments (schema names), hence I used VARIADIC arguments. The function looks like below -
CREATE FUNCTION f_fetch_tables(VARIADIC list text[])
RETURNS VOID
AS $$
DECLARE
begin_time TIMESTAMP;
expire_time TIMESTAMP;
BEGIN
/* To fetch the list of all objects from Redshift */
EXECUTE 'drop table if exists tmp_rs_obj_list;
create table tmp_rs_obj_list as
SELECT * FROM dblink(''rs_link'',$REDSHIFT$ select * from (select schemaname,
tablename from pg_tables UNION select schemaname, viewname from pg_views) where schemaname
not in (array_to_string($1,'','')) $REDSHIFT$) AS t1 (schema_nm varchar(30), obj_nm varchar(100))' using list;
END;
$$
LANGUAGE plpgsql
;
The function compiles fine and is created successfully, but I am not able to figure out a way to call it -
Used these calls so far, without any luck -
select f_fetch_tables('{public,pg_catalog}')
ERROR: there is no parameter $1
Where: Error occurred on dblink connection named "unnamed": could not
execute query.
select * from f_fetch_tables(VARIADIC '{public,pg_catalog}')
ERROR: there is no parameter $1
Where: Error occurred on dblink connection named "unnamed": could not execute query.
Any suggestions would be really helpful.
Thank you,
Kamlesh
There are a few issues with your function. I would suggest to use:
the function format() for easy passing the parameter,
dollar quoted ($fmt$) queries inside execute,
<> all(array) instead of not in operator (you do not have to convert an array to string).
The function with the suggested changes:
create or replace function f_fetch_tables(variadic list text[])
returns void
as $$
declare
begin_time timestamp;
expire_time timestamp;
begin
/* to fetch the list of all objects from redshift */
execute format($fmt$
drop table if exists tmp_rs_obj_list;
create table tmp_rs_obj_list as
select *
from dblink(
'rs_link', $redshift$
select *
from (
select schemaname, tablename
from pg_tables
union
select schemaname, viewname
from pg_views) s
where schemaname <> all(%L)
$redshift$)
as t1 (schema_nm varchar(30), obj_nm varchar(100))
$fmt$, list);
end;
$$
language plpgsql;
Note also the proper way of passing arguments to a function with variadic parameter:
select f_fetch_tables('pg_catalog', 'information_schema');
select * from tmp_rs_obj_list;
This issue is not related to variadic parameters - same behave you will get if you use normal parameters too. It is related to dynamic SQL - the queries executed by EXECUTE command from PLpgSQL has own parameter's environment. So you cannot to use variables or param references from function's environment.
This code doesn't work:
CREATE OR REPLACE FUNCTION fx(a int)
RETURNS void AS $$
BEGIN
EXECUTE 'SELECT * FROM foo WHERE foo.a = $1';
END;
$$ LANGUAGE plpgsql;
In this case, there was not passed any parameter to executed query. $1 is not valid. You should to use a USING clause, when you would to pass some parameters to dynamic SQL.
This code should to work:
CREATE OR REPLACE FUNCTION fx(a int)
RETURNS void AS $$
BEGIN
EXECUTE 'SELECT * FROM foo WHERE foo.a = $1' USING a;
END;
$$ LANGUAGE plpgsql;
But it doesn't to solve your problem too, because you are using USING clause. But you are use USING clause only on level EXECUTE command - not on dblink level - where it is not supported. dblink API has not nothing similar to USING clause of EXECUTE command. So you have to build native SQL string with unpacked (preevaluated) parameters before you will sent it to dblink API.
You are using two levels of dynamic SQL
EXECUTE
dblink
dblink doesn't support query parametrization - so you should not to use parameter place holders there .. $x.
In this case is better to serialize a input array to string in top plpgsql level and pass this string like dynamic SQL parameter.
DECLARE serialized_params text;
BEGIN
serialized_params = (SELECT array_agg(quote_literal(quote_ident(v))) FROM unnest(ARRAY['A','b']) g(v));
EXECUTE ' ....' USING serialized_params;
END
I want to pass a user defined type parameter to a PLPGSQL function, but I am getting this error at runtime:
dev=# select process_shapes();
ERROR: invalid input syntax for integer: "(,,7)"
CONTEXT: PL/pgSQL function process_shapes() line 9 at SQL statement
dev=#
For some reason, the parameters are not passed correctly and I have no idea why it doesn't work.
My functions are:
CREATE OR REPLACE FUNCTION join_shapes(first_shape shape_t,second_shape shape_t,OUT new_shape shape_t)
AS $$
DECLARE
BEGIN -- simplified join_shape()s function
new_shape.num_lines:=first_shape.num_lines+second_shape.num_lines;
END;
$$ LANGUAGE PLPGSQL;
CREATE OR REPLACE FUNCTION process_shapes()
RETURNS void AS $$
DECLARE
rectangle shape_t;
triangle shape_t;
produced_shape shape_t;
BEGIN
rectangle.num_lines:=4;
triangle.num_lines:=3;
SELECT join_shapes(rectangle,triangle) INTO produced_shape;
RAISE NOTICE 'produced shape = %s',produced_shape;
END;
$$ LANGUAGE PLPGSQL;
Type definition:
CREATE TYPE shape_t AS (
shape_id integer,
shape_name varchar,
num_lines integer
);
Postgres version: 9.6.1
When the target of a SELECT ... INTO statement is of a composite type, it will assign each of the columns returned by the SELECT to a different field in the target.
However, SELECT join_shapes(rectangle,triangle) returns a single column of type shape_t, and it's trying to cram the whole thing into the first column of the target, i.e. produced_shape.shape_id (hence the error message about a failed integer conversion).
Instead, you need a SELECT statement which returns three columns. Just replace
SELECT join_shapes(rectangle,triangle)
with
SELECT * FROM join_shapes(rectangle,triangle)
Alternatively, you could use
produced_shape := (SELECT join_shapes(rectangle,triangle));
which performs a single assignment, rather than trying to assign the target fields individually.
For other people whom want to pass composite types to functions:
create type pref_public.create_test_row_input as (
name text
);
create or replace function pref_public.create_test_row(test_row pref_public.create_test_row_input) returns pref_public.test_rows as $$
insert into pref_public.test_rows (name)
values
(test_row.name)
returning *;
$$ language sql strict security definer;
grant execute on function pref_public.create_test_row to pref_user;
You'll need to use row()
select * from pref_public.create_test_row(row('new row'));
More info here
I'm new to pgsql. I just want to use a table name as a function parameter in pgsql.
CREATE OR REPLACE FUNCTION user_test_table_name_as_input (table_name text)
RETURNS VOID
LANGUAGE plpgsql
AS $$
DECLARE
i int;
BEGIN
FOR i IN EXECUTE 'SELECT DISTINCT category FROM' || quote_ident(table_name)
LOOP
RAISE NOTICE '%', i;
END LOOP;
END
$$
When I try to use this function...
SELECT user_test_table_name_as_input (table_name);
...i get this error:
ERROR: column "table_name" does not exist
SQL state: 42703
I read the related threads, like Table name as a PostgreSQL function parameter, but the other proposed solutions (Concatenation, format() ), do not work for me, neither. Any idea?
'table_name' needs quotes as the argument to the call of your stored procedure - it's text.
I have an error, but I don't know what the problem is.
I want execute a function and return a value from a column filled in by the column default, a sequence - the equivalent of currval(sequence).
I use:
PostgreSQL 9.0
pgAdmin III
CREATE OR REPLACE FUNCTION name_function(in param_1 character varying
, out param_2 bigint)
AS
$$
BEGIN
INSERT INTO table (collumn_seq,param_1) VALUES (DEFAULT,param_1)
returning collumn_seq;
--where:collumn_seq reference a collumn serial..
END;
$$
LANGUAGE plpgsql VOLATILE;
I can create the function without error but when trying to execute, the following error is returned:
SELECT name_function('GHGHGH');
ERROR: The query has no destination for result data
It would work like this:
CREATE OR REPLACE FUNCTION name_function(param_1 varchar
, OUT param_2 bigint)
LANGUAGE plpgsql AS
$func$
BEGIN
INSERT INTO table (collumn_seq, param_1) -- "param_1" also the column name?
VALUES (DEFAULT, param_1)
RETURNING collumn_seq
INTO param2;
END
$func$;
Normally, you would add a RETURN statement, but with OUT parameters, this is optional.
Refer to the manual for more details:
Returning from a function
Executing a Query with a Single-row Result
The simple case can be covered with a plain SQL function.
And you can omit the target column that shall get its DEFAULT value.
And you can just as well use a RETURNS clause in this case:
CREATE OR REPLACE FUNCTION name_function(param_1 varchar)
RETURNS bigint
LANGUAGE sql AS
$func$
INSERT INTO table (param_1) -- "param_1" also the column name?
VALUES (param_1)
RETURNING collumn_seq;
$func$;