In postgresql how to change the value in jsonb type cloumn? - postgresql

Now I want to use postgresql function to change the jsonb type cloumn's value,now I have a function achieve the type json
CREATE OR REPLACE FUNCTION "json_object_set_key"(
"json" json,
"key_to_set" TEXT,
"value_to_set" anyelement
)
RETURNS json
LANGUAGE sql
IMMUTABLE
STRICT
AS $function$
SELECT COALESCE(
(SELECT ('{' || string_agg(to_json("key") || ':' || "value", ',') || '}')
FROM (SELECT *
FROM json_each("json")
WHERE "key" <> "key_to_set"
UNION ALL
SELECT "key_to_set", to_json("value_to_set")) AS "fields"),
'{}'
)::json
$function$;
but I unable to change the json type to jsonb,Now I want a function "jsonb_object_set_key" who can achieve, please help me,thank you very much.

just change the return data type:
t=# DROP FUNCTION jsonb_object_set_key(json,text,anyelement);
DROP FUNCTION
t=# CREATE OR REPLACE FUNCTION "jsonb_object_set_key"(
t(# "jsonb" jsonb,
t(# "key_to_set" TEXT,
t(# "value_to_set" anyelement
t(# )
t-# RETURNS jsonb
t-# LANGUAGE sql
t-# IMMUTABLE
t-# STRICT
t-# AS $function$
t$# SELECT COALESCE(
t$# (SELECT ('{' || string_agg(to_json("key") || ':' || "value", ',') || '}')
t$# FROM (SELECT *
t$# FROM jsonb_each("jsonb")
t$# WHERE "key" <> "key_to_set"
t$# UNION ALL
t$# SELECT "key_to_set", to_jsonb("value_to_set")) AS "fields"),
t$# '{}'
t$# )::jsonb
t$# $function$;
CREATE FUNCTION
here it goes:
t=# select pg_typeof(jsonb_object_set_key('{"a":3}','a',5));
jsonb
alse if you have at least 9.5 concider using jsonb_set: https://www.postgresql.org/docs/current/static/functions-json.html

Related

ERROR: column "file_name" does not exist LINE 1: SELECT distinct(file_name) , uploaded_date, .. Postgresql dynamic sub query

create or replace function get_value2(tbl varchar, tbl1 anyelement) RETURNS
refcursor AS
$$
declare
ref_cursor REFCURSOR;
--refcursor declaration
begin
OPEN ref_cursor FOR EXECUTE
'SELECT distinct(file_name) , uploaded_date, ' ||'(SELECT STRING_AGG(column_name, ',')
from information_schema.columns
where table_name =' || quote_literal(tbl) ')' ||
'FROM ' || pg_typeof(tbl1); --table name from parameter
RETURN (ref_cursor);
end;
$$ LANGUAGE plpgsql;
--pg_typeof(tbl1) table name from parameter
any help will be appreciated

Use parameter inside subquery

How can i use my parameters inside a subquery with ' '? (Postgres v.10)
create or replace function test(p_1 character varying, p_2 character varying)
returns table (id integer, total integer, fruit character varying)
LANGUAGE plpgsql
AS $$
begin
return query
Select * from dblink(
'host=myhost
user=myuser
password=mypw
dbname=mydb',
'select id,total,fruit from fruits
where fruit in (p_1,p_2)') as x(id integer,total integer,fruit varchar);
end;
$$
If i call the function
select * from test('apple','orange')
I get this ERROR: colum "p_1" and "p_2" does not exist..
Instead of saying p_1 it's possible to call parameters with $ signs or something. I don't know if that's the real approach but i can't find any documentation about it anywhere?
You can try this (not tested) :
return query
Select * from dblink(
'host=myhost
user=myuser
password=mypw
dbname=mydb',
'select id,total,fruit from fruits
where fruit in (' || p_1 || ',' || p_2 || ')') as x(id integer,total integer,fruit varchar);

How to return any* type from postgres function?

I can returns setof record and provide definition list to get result:
select (f.row).* from tree( 'resource_type' ) f( id int, path int[], fullname text, level int, row resource_type );
But how to rewrite my function to return any type with automatic cast?
This does not work:
create or replace function tree( _tbl regclass )
--returns setof record
returns table( id int, path int[], fullname text, level int, r record )
as $$
BEGIN
return query execute format( '
WITH RECURSIVE parent ( id, path, fullname, level, row ) AS (
SELECT
id,
ARRAY[ id ],
''/'' || name::text,
1,
%1$s
FROM %1$s
WHERE parent_id = 13
UNION ALL
SELECT
child.id,
parent.path || child.id,
parent.fullname || ''/'' || child.name,
parent.level +1,
child
FROM parent
JOIN %1$s child ON parent.id = child.parent_id
WHERE NOT child.id = ANY(path)
)
SELECT * FROM parent ', _tbl);
END;
$$ LANGUAGE plpgsql
=> select f.r from tree( 'resource_type' ) f
ERROR: structure of query does not match function result type
DETAIL: Returned type resource_type does not match expected type record in column 5.
CONTEXT: PL/pgSQL function tree(regclass) line 3 at RETURN QUERY
The way to write a polymorphic function is to use anyelement. But you must provide an argument of type anyelement as well. The actual data type will then be deduced from the type of that argument:
CREATE FUNCTION poly(
outtype anyelement,
otherparam integer
) RETURNS TABLE (res anyelement)
LANGUAGE plpgsql AS
$$DECLARE
resulttype regtype := pg_typeof(outtype);
whetever text;
BEGIN
/* calculate a text representation of the result in "whatever" */
EXECUTE format('SELECT CAST ($1 AS %s)', resulttype)
USING whatever INTO res;
RETURN NEXT;
END;$$
You call a function like this by supplying a dummy argument of the desired type:
SELECT * FROM poly(NULL::myresulttype, 42);
The solution is to pass anyelement as argument, then I can use anyelement for returns ... statement. doc
create or replace function tree( _tbl anyelement )
returns table( id int, path int[], fullname text, level int, "row" anyelement )
as $$
BEGIN
return query execute format( '...', pg_typeof( _tbl )::text );
END;
$$ LANGUAGE plpgsql

How I can return all fields from procedure?

Now I have the following procedure:
CREATE OR REPLACE FUNCTION find_city_by_name(match varchar) RETURNS TABLE(city_name varchar) LANGUAGE plpgsql as $$
BEGIN
RETURN QUERY WITH r AS (
SELECT short_name FROM geo_cities WHERE short_name ILIKE CONCAT(match, '%')
)
SELECT r.short_name FROM r;
END;
$$
I want return all fields (*) (not only short_name). What I need to change in my procedure?
Here is a simplified (w/o WITH and with language sql) version, that I've mentioned in my comment to the adjacent answer:
create or replace function find_city_by_name(text)
returns table(city_name varchar, long_name varchar)
as $$
select * from geo_cities where short_name ilike $1 || '%';
$$ language sql;
Also, you might find it more convenient to refer to the geo_cities table itself defining the function's signature, using SETOF geo_cities:
create or replace function find_city_by_name(text)
returns setof geo_cities
as $$
select * from geo_cities where short_name ilike $1 || '%';
$$ language sql;
-- this will allow you to change the structure of geo_cities table w/o necessity to change the function's definition.
If you want a real row you must to explicit declare all fields in the return clausule:
create table geo_cities (
short_name varchar,
long_name varchar
);
insert into geo_cities values ('BERLIN', 'BERLIN'), ('BERLIN 2','BERLIN TWO');
CREATE OR REPLACE FUNCTION find_city_by_name(match varchar)
RETURNS TABLE(city_name varchar, long_name varchar)
LANGUAGE plpgsql
AS
$$
BEGIN
RETURN QUERY WITH r AS (
SELECT * FROM geo_cities WHERE short_name ILIKE CONCAT(match, '%')
)
SELECT * FROM r;
END;
$$;
select * from find_city_by_name('BERLIN');
See the example running at: http://rextester.com/IKTT52978

postgresql - null value error on function

I'm trying to figure out how to resolve this ERROR: null values cannot be formatted as an SQL identifier when trying to select my function:
select * from store_keys();
ERROR: null values cannot be formatted as an SQL identifier
CONTEXT: SQL statement "SELECT string_agg(
format('SELECT %1$I, count(email_store_key), email_store_key, form_created_datetime
FROM %1$I where email_store_key=0 GROUP BY 3, 4', tbl_name),
' UNION ') FROM information_schema.tables
WHERE table_schema = 'abc_dev_sch_1234'
AND table_name LIKE 'fact_%'"
The base query it uses, does not produce null values. So where is this coming from??
select count(email_store_key), email_store_key, form_created_datetime
FROM <table_name> where email_store_key=0 GROUP BY email_store_key, form_created_datetime;
Here's my create statement:
DROP FUNCTION store_keys();
CREATE OR REPLACE FUNCTION store_keys()
RETURNS TABLE (tbl_name varchar, count_keys bigint, email_store_key integer, form_created_datetime timestamp)
AS $$
DECLARE
qry text;
BEGIN
SELECT string_agg(
format('SELECT %1$I, count(email_store_key), email_store_key, form_created_datetime
FROM %1$I where email_store_key=0 GROUP BY 3, 4', tbl_name),
' UNION ') INTO qry
FROM information_schema.tables
WHERE table_schema = 'abc_dev_sch_1234'
AND table_name LIKE 'fact_%';
RETURN QUERY EXECUTE qry;
END
$$ LANGUAGE plpgsql;