Unexpected end of input in Postgresql stored procedure multidimensial array parameter - postgresql

I have built stored procedure in PostgreSql which accept multidimensial array parameters like below
SELECT horecami.insert_obj_common(
'{"(5, 2, LLLLL rest, 46181, a#a.com, ooo, kkk, 12:09, 20:40, 23, true, 49.667, 48.232, fu, 2011-12-15 15:28:19+04, 2011-12-15 15:28:19+04, 3, 1)"}'::obj_special[],
'{"(1, 3, q1, q2, q3, q4, qson latest, true, 2011-12-15 15:28:19+04, 2, 2, 3, 2011-12-15 15:28:19+04, ' || '{"(1, 1, 1, 1, 1)"}'::horecami.obj_soft_hardware[] || ')"}'::obj_soft[]
);
Inside this procedure there ara foreach loops that works without problem.
But when i added last extra parametr as array (horecami.obj_soft_hardware[]) it gives me malformed array error.
This is error
ERROR: malformed array literal: "{"(1, 3, q1, q2, q3, q4, qson latest, true, 2011-12-15 15:28:19+04, 2, 2, 3, 2011-12-15 15:28:19+04, "
LINE 3: '{"(1, 3, q1, q2, q3, q4, qson latest, true, 2011-12-15 1...
^
DETAIL: Unexpected end of input.
SQL state: 22P02
Character: 202
It must return number
I guess this syntac error.
Thanks beforehands.

You don't have a multi-dimensional array; you've got an array containing a composite type, which in turn contains an array containing a composite type.
When writing this as a string literal, certain characters have to be escaped (e.g. strings with spaces need quotes, and those quotes need escaping). Then at nested levels they all need to be double quoted and escaped.
To determine what the string literal should look like, just create it using actual arrays and rows (or composite types), then cast to text to get the literal string value with all fields correctly quoted and escaped:
SELECT ARRAY[ROW(1, 3, 'q1', 'q2', 'q3', 'q4', 'qson latest', ARRAY[ROW(1, 1, 1, 1, 1)])]::TEXT
Returns:
{"(1,3,q1,q2,q3,q4,\"qson latest\",\"{\"\"(1,1,1,1,1)\"\"}\")"}

Related

Different path formats for PostgreSQL JSONB functions

I'm confused by how path uses different formats depending on the function in the PostgreSQL JSONB documentation.
If I had a PostgreSQL table foo that looks like
pk
json_obj
0
{"values": [{"id": "a_b", "value": 5}, {"id": "c_d", "value": 6]}
1
{"values": [{"id": "c_d", "value": 7}, {"id": "e_f", "value": 8]}
Why does this query give me these results?
SELECT json_obj, -- {"values": [{"id": "a_b", "value": 5}, {"id": "c_d", "value": 6]}
json_obj #? '$.values[*].id', -- true
json_obj #> '$.values[*].id', -- ERROR: malformed array literal
json_obj #> '{values, 0, id}', -- "a_b"
JSONB_SET(json_obj, '$.annotations[*].id', '"hi"') -- ERROR: malformed array literal
FROM foo;
Specifically, why does #? support $.values[*].id (described on that page in another section) but JSONB_SET uses some other path format {bar,3,baz}?
Ultimately, what I would like to do and don't know how, is to remove non-alphanumeric characters (e.g. underscores in this example) in all id values represented by the path $.values[*].id.
The reason is that the operators have different data types on the right hand side.
SELECT oprname, oprright::regtype
FROM pg_operator
WHERE oprleft = 'jsonb'::regtype
AND oprname IN ('#?', '#>');
oprname | oprright
---------+----------
#> | text[]
#? | jsonpath
(2 rows)
Similarly, the second argument of jsonb_set is a text[].
Now '$.values[*].id' is a valid jsonpath, but not a valid text[] literal.
Thanks for the answers and comments about why the data types were different.
I wanted to post how I solved my problem:
Ultimately, what I would like to do and don't know how, is to remove
non-alphanumeric characters (e.g. underscores in this example) in all
id values represented by the path $.values[*].id.
WITH unnested AS (
SELECT f.pk, JSONB_ARRAY_ELEMENTS(f.json_obj -> 'values') AS value
FROM foo f
),
updated_values AS (
SELECT un.pk, JSONB_SET(un.value, '{id}', TO_JSONB(LOWER(REGEXP_REPLACE(un.value ->> 'id', '[^a-zA-Z0-9]', '', 'g'))), FALSE) AS new_value
FROM unnested un
WHERE value -> 'id' IS NOT NULL -- Had some values that didn't have 'id' keys
)
UPDATE foo f2
SET json_obj = JSONB_SET(f2.json_obj, '{values}', (SELECT JSONB_AGG(uv.new_value) FROM updated_values uv WHERE uv.pk = f2.pk), FALSE)
WHERE JSONB_PATH_EXISTS(f2.json_obj, '$.values[*].id') -- Had some values that didn't have 'id' keys

postgres 10 - convert categorical column to presence absence matrix

I'd like to create a new table like so:
original table:
site_id, site_period
1, period_a
2, period_b
2, period_c
3, period_d
4, period_a
4, period_b
desired table:
site_id, period_a, period_b, period_c, period_d
1, 1, 0, 0, 0
2, 0, 1, 1, 0
3, 0, 0, 0, 1
4, 1, 1, 0, 0
This is probably a duplicate question as this is a relatively simple problem, but I didn't know what vocabulary to use to describe it to find a solution. I'm familiar with coding logic, but not terribly comfortable with sql queries. Thanks!
You can use CREATE TABLE ... AS SELECT and conditional aggregation.
CREATE TABLE desiredtable
AS
SELECT site_id,
count(CASE site_period
WHEN 'period_a' THEN
1
END) period_a,
...
count(CASE site_period
WHEN 'period_d' THEN
1
END) period_d
FROM originaltable
GROUP BY site_id;

Need to add commas to a list of numbers with regexp_replace (Postgresql)

I'm trying to write a postgres function that will sanitize a list of numbers into a list of comma-separated numbers. These numbers are being entered into an input field. I want to allow users to just enter a line of space-separated numbers (ex: 1 3 4 12) and have it change it to 1,3,4,12.
But, if they do enter it correctly (ex: 1,3,4,12 or 1, 3, 4, 12), I still want it to sanitize it to 1,3,4,12. I also have to account for things like (ex: 1, 3 4, 12).
This is what I'm currently doing:
select regexp_replace(trim(list_of_numbers), '[^0-9.] | [^,]', ',', 'g')
If I have a list like this:
select regexp_replace(trim('1, 2, 4, 14'), '[^0-9.] | [^,]', ',', 'g')
it returns : "1,2,4,14" so that's good.
But, if I have a list like this:
select regexp_replace(trim('1 2 4 14'), '[^0-9.] | [^,]', ',', 'g')
it returns : "1,,,4"
If you change your regex to [^0-9.]+ it'll replace all non-numerics (i.e. , ,, ,) with a ,.
Try it out here
I think the best option is to convert to an array using regexp_split_to_array then turn that back into a string:
The following:
with t(input) as (
values
('1 3 4 12'),
('1,3,4,12'),
('1, 3 4, 12'),
('1,3,4,12'),
('1 3 4 , 12'),
(' 1, 2 , 4 12 ')
)
select array_to_string(regexp_split_to_array(trim(input),'(\s+)|(\s*,\s*)'), ',')
from t;
returns:
array_to_string
---------------
1,3,4,12
1,3,4,12
1,3,4,12
1,3,4,12
1,3,4,12
1,3,4,12
You could split the string on any amount of whitespace or commas (,|\s)+ and join it back together using commas:
select array_to_string(regexp_split_to_array('1 2 4 14', '(,|\s)+'), ', ');

What does the exclude_nodata_value argument to ST_DumpValues do?

Could anyone explain what the exclude_nodata_value argument to ST_DumpValues does?
For example, given the following:
WITH
-- Create a raster 4x4 raster, with each value set to 8 and NODATA set to -99.
tbl_1 AS (
SELECT
ST_AddBand(
ST_MakeEmptyRaster(4, 4, 0, 0, 1, -1, 0, 0, 4326),
1, '32BF', 8, -99
) AS rast
),
-- Set the values in rows 1 and 2 to -99.
tbl_2 AS (
SELECT
ST_SetValues(
rast, 1, 1, 1, 4, 2, -99, FALSE
) AS rast FROM tbl_1)
Why does the following select statement return NULLs in the first two rows:
SELECT ST_DumpValues(rast, 1, TRUE) AS cell_values FROM tbl_2;
Like this:
{{NULL,NULL,NULL,NULL},{NULL,NULL,NULL,NULL},{8,8,8,8},{8,8,8,8}}
But the following select statement return -99s?
SELECT ST_DumpValues(rast, 1, FALSE) AS cell_values FROM tbl_2;
Like this:
{{-99,-99,-99,-99},{-99,-99,-99,-99},{8,8,8,8},{8,8,8,8}}
Clearly, with both statements the first two rows really contain -99s. However, in the first case (exclude_nodata_value=TRUE) these values have been masked (but not replaced) by NULLS.
Thanks for any help. The subtle differences between NULL and NODATA within PostGIS have been driving me crazy for several days.

Postgresql prepare statement with operator ANY

SELECT * FROM tbl_emp WHERE interest = $1 AND emp_id = ANY(?)
Is the above statement correct to be used in function PQprepare?
If yes, what should be the value for nParams and how would PQexecPrepared be called?
Regards,
Mayank
If you're trying to prepare something like = ANY (1, 2, 3), this won't work directly, because 1, 2, 3 is a syntactic construct, and not an expression. (Of course you could do = ANY ($2, $3, $4), but that only works if you know exactly how many values you have.)
But you can do it with arrays. The above is equivalent to = ANY(ARRAY[1, 2, 3]), and so you'd write
SELECT * FROM tbl_emp WHERE interest = $1 AND emp_id = ANY($2)
and the types of the parameters are, say, int and int[].
To call PQexecPrepared, you will need an array as string literal. Something like "{1, 2, 3}" (as a C string) will do. See the documentation for details.