SQL Server function PATINDEX in PostgreSQL? - postgresql

In SQL Server I execute:
select PATINDEX('%\%[0123456789][\ ]%', N'\deftab1134\paperw12240\paperh20000\margl900\margt1440\margr540\margb1440\plain\f1\fs24 That is my report');
---
1
It is correct. I need the same function in PostgreSQL.
I have found this function:
CREATE OR REPLACE FUNCTION patindex( "pattern" TEXT, "expression" TEXT)
RETURNS INT
AS $BODY$
SELECT
COALESCE(
STRPOS(
lower($2)
,(
SELECT
lower(( REGEXP_MATCHES(
lower($2)
,'(' || REPLACE( REPLACE( lower(TRIM( $1, '%' )), '%', '.*?' ), '_', '.' ) || ')'
) )[ 1 ])
LIMIT 1
)
)
,0
)
;
$BODY$ LANGUAGE 'sql' IMMUTABLE;
But it works incorrectly with the same parameters:
select helper2_patindex('%\%[0123456789][\ ]%',
'\deftab1134\paperw12240\paperh20000\margl900\margt1440\margr540\margb1440\plain\f1\fs24 That is my report');
----
87
What is incorrect? what can I fix?

Related

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

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

POSTGRESQL: Function result with Concat value

I'm trying to create function with result of concatenated value.
see below:
CREATE OR REPLACE FUNCTION select_name()
RETURNS TABLE(name text ) AS
$BODY$
BEGIN
RETURN QUERY
select
cast(first_name as text) ||' ' || cast( middle_name as text) ||' ' || cast(last_name as text) as name
from table_name;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
However upon querying
select * from select_name();
it shows error:
ERROR: relation "select_name" does not exist
LINE 8: select * from select_name
^
********** Error **********
ERROR: relation "select_name" does not exist
SQL state: 42P01
Character: 159
I'm stuck here.
Please help.
I tried to used below statement, and it worked. ^_^
select
cast( first_name ||' ' || middle_name ||' ' || last_name as text) as name
from table_name;
Try this out this will go like a fly.
CREATE OR REPLACE FUNCTION select_name()
RETURNS TABLE(name text ) AS
$$
BEGIN
RETURN QUERY
select
select
cast(first_name as text) ||' ' || cast( middle_name as text) ||' ' || cast(last_name as text) as name
from table_name;
END;
$$ LANGUAGE plpgsql;

Postgresql function return multiple select statements

Can any one of you tell me how to approach this:
CREATE OR REPLACE FUNCTION name()
RETURNS ????? AS
$func$
BEGIN
SELECT * FROM tbl_a a;
SELECT * FROM tbl_b b;
END
$func$ LANGUAGE plpgsql;
Both tables have different structures.
You can use cursors but I can hardly imagine why you need such a function.
CREATE OR REPLACE FUNCTION my_multiselect(refcursor, refcursor) RETURNS VOID AS
$func$
BEGIN
OPEN $1 FOR SELECT * FROM information_schema.routines;
OPEN $2 FOR SELECT * FROM information_schema.sequences;
END
$func$ LANGUAGE plpgsql;
BEGIN;
SELECT my_multiselect('first_cursor_to_routines', 'second_cursor_to_sequences');
FETCH ALL IN first_cursor_to_routines;
FETCH ALL IN second_cursor_to_sequences;
COMMIT;
I'm not really sure what you're doing with this, but it sounds like you just want to return a union of these distinct result sets. You can do this with a dynamic query. I'm using Postgres 9.4.
CREATE OR REPLACE FUNCTION make_query(IN p_tables text[])
RETURNS void AS
$BODY$
DECLARE
v_qry text;
v_cols text;
v_types text;
v_as text;
BEGIN
EXECUTE format('
WITH sub AS (
SELECT
table_name,
column_name,
data_type
FROM
information_schema.columns
WHERE
table_name = ANY(%L)
ORDER BY
table_name,
ordinal_position)
,sub2 AS(
SELECT
DISTINCT ON (column_name, data_type)
column_name || '' '' || data_type AS def
FROM
sub
)
SELECT
string_agg(def, '','')
FROM
sub2;
',
p_tables
) INTO v_types;
v_qry := '
CREATE OR REPLACE FUNCTION name()
RETURNS TABLE(' || v_types || ') AS
$func$';
FOR i IN 1..array_upper(p_tables, 1)
LOOP
v_as := 'tbl' || i;
EXECUTE format('
WITH sub AS (
SELECT
table_name,
column_name,
data_type
FROM
information_schema.columns
WHERE
table_name = ANY(%L)
ORDER BY
table_name,
ordinal_position)
,sub2 AS(
SELECT
DISTINCT ON (column_name, data_type)
CASE WHEN table_name = ''%I''
THEN %L || ''.'' || column_name
ELSE ''NULL::'' || data_type
END AS cols
FROM
sub
)
SELECT
string_agg(cols, '','')
FROM
sub2;
',
p_tables,
p_tables[i],
v_as
) INTO v_cols;
IF i > 1 THEN
v_qry := v_qry || '
UNION ALL';
END IF;
v_qry := v_qry || '
SELECT ' || v_cols || ' FROM ' || p_tables[i] || ' AS ' || v_as;
IF i = array_upper(p_tables, 1) THEN
v_qry := v_qry || ';';
END IF;
END LOOP;
v_qry := v_qry || '
$func$ LANGUAGE sql;
';
EXECUTE v_qry;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
Sorry it looks ugly here, but this formatting helps the final product look nicer. If you're shy about executing a dynamic query like this off the bat, just replace EXECUTE v_qry; with RAISE INFO 'v_qry: %', v_qry; and it will simply print the dynamic query out in a message without executing it, so you can review what it will do once executed.
Then execute make_query() with a list of tables you want to display like this:
SELECT make_query(ARRAY['tbl_a', 'tbl_b']);
The result is that you will now have a function called name() which you can call in order to see the results of both tables at the same time, with all the union details already sorted out:
SELECT * FROM name();

how can I insert data by declaring all fields (not *)?

Here's my insert query:
INSERT INTO listing_replica_child (
(
SELECT rtz_comma_list(column_name)
FROM information_schema.columns
WHERE table_name = 'listing'
)
)
VALUES (
(
SELECT (
(
SELECT rtz_comma_list(column_name)
FROM information_schema.columns
WHERE table_name = 'listing'
)
FROM listing
WHERE listing_id = 9656
)
)
);
I'm using postgres.
do $$
DECLARE rec TEXT;
BEGIN
SELECT 'insert into listing_replica_child (' || t.col || ') select * from listing WHERE listing_id = 9656 '
INTO rec
FROM (
SELECT string_agg(column_name, ',') col
FROM information_schema.columns
WHERE table_name = 'listing'
) t;
EXECUTE rec;
END;$$;
You can wrap this dynamic query into a function like this
CREATE OR replace FUNCTION insert_listing_replica_child (_listing_id INT)
RETURNS void AS $$
DECLARE rec TEXT;
BEGIN
SELECT 'insert into listing_replica_child (' || t.col || ') select * from listing WHERE listing_id = ' || _listing_id || ' '
INTO rec
FROM (
SELECT string_agg(column_name, ',') col
FROM information_schema.columns
WHERE table_name = 'listing'
) t;
EXECUTE rec;
END $$
LANGUAGE plpgsql
So if want to insert values from listing table with lissting_id=9656 into table listing_replica_child
just Call
select insert_listing_replica_child (9656)
The way to specify all destination fields is to omit the column list entirely.
Your attempt then becomes:
INSERT INTO listing_replica_child
SELECT * FROM listing
WHERE listing_id = 9656
without loss of intention: If the number and type of the fields of the tables differs with your attempt, execution will explode (as will this query).
Even though you have asked that * not be used, it is the simplest and best way to achieve the task.

PostgreSQL 9.0 issues with function

Here is the function I am working with:
CREATE OR REPLACE FUNCTION f_multiply_row(_tbl regclass
, _idname text
, _minid int
, _maxid int)
RETURNS void AS
$func$
BEGIN
EXECUTE (
SELECT format('INSERT INTO %1$s (%2$I, %3$s)
SELECT g.g, %3$s
FROM (SELECT * FROM %1$s LIMIT 1) t
,generate_series($1, $2) g(g)'::text
, _tbl
, _idname
, string_agg(quote_ident(attname), ', ')
)
FROM pg_attribute
WHERE attrelid = _tbl
AND attname <> _idname -- exclude id column
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0 -- no system columns
)
USING _minid, _maxid;
END
$func$ LANGUAGE plpgsql;
SELECT f_multiply_row('campaign', 'campaign_id', 50, 500);
Obviously PSQL 9.0 does NOT have the format method (introduced in 9.1), so I am trying to convert the method to work in 9.0 and am having the hardest time getting it to work.
Error : ERROR: function format(text, regclass, text, text) does not exist
LINE 2: SELECT format('INSERT INTO %1$s (%2$I, %3$s)
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
So, I attempted to rewrite it in 9.0 style:
CREATE OR REPLACE FUNCTION f_multiply_row()
RETURNS void AS
$func$
DECLARE
_tbl regclass := quote_ident('campaign');
_idname text := 'campaign_id';
_minid int := 50;
_maxid int := 500;
BEGIN
EXECUTE (
'SELECT INSERT INTO ' || _tbl || ' ($1, $2)
SELECT g.g $3 FROM (SELECT * FROM ' || _tbl || ' LIMIT 1) t, generate_series($1, $2) g(g)'
USING _tbl, _idname, string_agg(quote_ident(attname, ', '))
FROM pg_attribute
WHERE attrelid = _tbl
AND attname <> _idname -- exclude id column
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0 -- no system columns
);
END
$func$ LANGUAGE plpgsql;
SELECT f_multiply_row();
But, the above causes these two errors:
Error : ERROR: syntax error at or near "USING"
LINE 15: USING _tbl, _idname, string_agg(quote_ident(attname, ', ')...
^
AND
Error : ERROR: function f_multiply_row() does not exist
LINE 1: SELECT f_multiply_row()
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.