Postgresql transform multidimensional array to relational model - postgresql

I have seeing this example multiple times but only on a single column
INSERT INTO user_subservices(user_id, subservice_id)
SELECT 1 id, x
FROM unnest(ARRAY[1,2,3,4,5,6,7,8,22,33]) x
I need to insert multiple columns with multidimensional array like:
INSERT INTO items(order_id,lot_serial,pallets,oum) VALUES from Array
Array example:
[[3,'Fff767',89,'Boxes'],[3,'FDH6784',45,'Boxes'],[3,'FDH6788',97,'Boxes']...]
What would be the approach to do this with Postgresql 9.4.5

You can create reduce_dim function to unnest ultidimensional array.
See https://wiki.postgresql.org/wiki/Unnest_multidimensional_array
CREATE OR REPLACE FUNCTION public.reduce_dim(anyarray)
RETURNS SETOF anyarray AS
$function$
DECLARE
s $1%TYPE;
BEGIN
FOREACH s SLICE 1 IN ARRAY $1 LOOP
RETURN NEXT s;
END LOOP;
RETURN;
END;
$function$
LANGUAGE plpgsql IMMUTABLE;
insert into items select t[1],t[2],t[3],t[4] from (select reduce_dim(reduce_dim(ARRAY[['3','Fff767','89','Boxes'],['3','FDH6784','45','Boxes'],['3','FDH6788','97','Boxes']])) t) as y;

Related

cut the content of a column before insertion PostgreSQL

I have a table photos which has two columns (name_photo and code_support) :
the result I'm looking for :
I would like to cut the data of the name_photo field which is separated by pipe so here is what I did:
CREATE OR REPLACE FUNCTION string_to_rows(text) RETURNS SETOF TEXT AS $$
DECLARE
elems text[];
BEGIN
elems := string_to_array($1, '|');
FOR i IN array_lower(elems, 1) .. array_upper(elems, 1) LOOP
RETURN NEXT elems[i];
END LOOP;
RETURN;
END
$$ LANGUAGE plpgsql;
now how can i use this function to crop my field before inserting into photo table? thank you in advance
You don't need to write a function for this. The built-in string_to_array and unnest() functions will do what you want:
select t.name, p.code_support
from photos p
cross join unnest(string_to_array(p.nom_photo, '|')) as t(name)
unnest() turns the elements of an array into rows.

In clause in postgres

Need Output from table with in clause in PostgreSQL
I tried to make loop or ids passed from my code. I did same to update the rows dynamically, but for select I m not getting values from DB
CREATE OR REPLACE FUNCTION dashboard.rspgetpendingdispatchbyaccountgroupidandbranchid(
IN accountgroupIdCol numeric(8,0),
IN branchidcol character varying
)
RETURNS void
AS
$$
DECLARE
ArrayText text[];
i int;
BEGIN
select string_to_array(branchidcol, ',') into ArrayText;
i := 1;
loop
if i > array_upper(ArrayText, 1) then
exit;
else
SELECT
pd.branchid,pd.totallr,pd.totalarticle,pd.totalweight,
pd.totalamount
FROM dashboard.pendingdispatch AS pd
WHERE
pd.accountgroupid = accountgroupIdCol AND pd.branchid IN(ArrayText[i]::numeric);
i := i + 1;
end if;
END LOOP;
END;
$$ LANGUAGE 'plpgsql' VOLATILE;
There is no need for a loop (or PL/pgSQL actually)
You can use the array directly in the query, e.g.:
where pd.branchid = any (string_to_array(branchidcol, ','));
But your function does not return anything, so obviously you won't get a result.
If you want to return the result of that SELECT query, you need to define the function as returns table (...) and then use return query - or even better make it a SQL function:
CREATE OR REPLACE FUNCTION dashboard.rspgetpendingdispatchbyaccountgroupidandbranchid(
IN accountgroupIdCol numeric(8,0),
IN branchidcol character varying )
RETURNS table(branchid integer, totallr integer, totalarticle integer, totalweight numeric, totalamount integer)
AS
$$
SELECT pd.branchid,pd.totallr,pd.totalarticle,pd.totalweight, pd.totalamount
FROM dashboard.pendingdispatch AS pd
WHERE pd.accountgroupid = accountgroupIdCol
AND pd.branchid = any (string_to_array(branchidcol, ',')::numeric[]);
$$
LANGUAGE sql
VOLATILE;
Note that I guessed the data types for the columns of the query based on their names. You have to adjust the line with returns table (...) to match the data types of the select columns.

Syntax error at or near "unnest"

This request:
unnest('{1,2}'::int[]);
gives to me this error:
syntax error at or near "unnest"
neither unnest('{1,2}'); works
Why?
intire:
CREATE OR REPLACE FUNCTION result() RETURNS setof users AS
$$
DECLARE
BEGIN
unnest('{1,2}'::int[]);
RETURN QUERY SELECT * FROM users;
END;
$$ LANGUAGE plpgsql;
SELECT result();
EDIT
The core idea:
To retrive and manipualate with the bigint[] which is stored inside in a column.
So, i have got this:
SELECT * FROM users WHERE email = email_ LIMIT 1 INTO usr;
Then, usr.chain contains some bigint[] data. For example, {1,2,3,4,5,6,7,8,9,10}. I want to save only the 4 last of them.
How to retrieve {7,8,9,10} and {1,2,3,4,5,6} and iterate over these arrays?
I only found the solution is to use SELECT FROM unnest(usr.chain) AS x ORDER BY x ASC LIMIT (sdl - mdl) OFFSET mchain and so on. but unnest function gives to me this stupid error. I'm really do not understand why it happends. It doesn't work in sucj easy case I wrote at the beginning of the question. subarray function doesn't work because of the data type is bigint[] not int[]
Futher more, the code unnest(ARRAY[1,2]) gives to me the same error.
http://www.postgresql.org/docs/9.2/static/functions-array.html
The same error for array_append function
to iterate over array:
CREATE OR REPLACE FUNCTION someresult(somearr bigint[] ) RETURNS setof bigint AS
$$
DECLARE
i integer;
x bigint;
BEGIN
for x in select unnest($1)
loop
-- do something
return next x;
end loop;
-- or
FOR i IN array_lower($1, 1) .. array_upper($1, 1)
LOOP
-- do something like:
return next ($1)[i];
end loop;
END;
$$ LANGUAGE plpgsql;
select someresult('{1,2,3,4}') ;
array_append ....
CREATE OR REPLACE FUNCTION someresult2(somearr bigint[],val bigint ) RETURNS bigint[] AS
$$
DECLARE
somenew_arr bigint[];
BEGIN
somenew_arr = array_append($1, $2 );
return somenew_arr;
END;
$$ LANGUAGE plpgsql;
select someresult2('{1,2,3,4}' ,222) ;
so, here you have basic example how to iterate and append arrays. Now can you write step by step what you want to do, to achieve .

Selecting from multidimensional array parameter in Postgres

I have a function that does an insert in a parent table then inserts into a child table. The last parameter is an array of variable length. I use this to do the insert into the child table by sending an array of comma delimited pairs and parsing these out.
create or replace function neil_test(time_stamp timestamp with time zone, type_id text, raw_message text,field_values text[])
returns void
AS $$
DECLARE
last_message_id bigint;
x text;
BEGIN
INSERT INTO message(time_stamp,type_id,raw_message) values(time_stamp,type_id,raw_message);
select into last_message_id currval(pg_get_serial_sequence('message', 'id'));
foreach x in ARRAY field_values
LOOP
insert into message_field_value(last_message_id,field_id,fieldValue) select left(x,strpos(x,',')-1), right(x,length(x)-strpos(x,','));
END LOOP;
END
$$LANGUAGE plpgsql
It's called like this:
select neil_test('2001-01-01 08:00:00.1234','F','RAW',ARRAY['One,value1','two,value2','three,value3'])
This works OK but what I'd really like to do is use the array directly. Something like :
select neil_test('2001-01-01 08:00:00.1234','F',
'RAW',ARRAY[['One', 'value1'],['two','value2'],['three','value3']])
...
insert into message_field_value(last_message_id,fieldid, field value)
select field_values[1], field_values[2]
I've tried the unnest function but this doesn't work as it seems to flatten out the whole array and I lose the pairs. Is something like this even possible with Postgres arrays?
Use SLICE in the FOREACH statement to iterate over elements of multidimencional array. Without SLICE it iterates over individual elements of the array. This works for me:
CREATE OR REPLACE FUNCTION neil_test2(time_stamp timestamp with time zone, type_id text, raw_message text,field_values text[][2])
RETURNS void
AS $$
DECLARE
last_message_id bigint;
x TEXT[];
BEGIN
INSERT INTO message(time_stamp,type_id,raw_message) VALUES (time_stamp,type_id,raw_message);
SELECT INTO last_message_id currval(pg_get_serial_sequence('message', 'id'));
FOREACH x SLICE 1 in ARRAY field_values LOOP
INSERT INTO message_field_value(last_message_id, field_id, field_value) SELECT last_message_id, x[1], x[2];
END LOOP;
END
$$LANGUAGE plpgsql;

INSERT while LOOPing

i'd like to insert some records into a table while looping. Records are passed as a varchar tab to a function ie.:
create function a(tab varchar[]) RETURNS void AS
$$
DECLARE
b varchar(20);
BEGIN
FOREACH b IN ARRAY tab
LOOP
INSERT INTO....;
END LOOP;
RETURN;
END;
$$
LANGUAGE plpgsql;
However, when executing there is the error:
ERROR: syntax error at or near "FOREACH"
LINE 1: FOREACH $1 IN ARRAY tab LOOP INSERT INTO x (c, ...
QUERY: FOREACH $1 IN ARRAY tab LOOP INSERT INTO x (c) VALUES ( $1)
CONTEXT: SQL statement in PL/PgSQL function " near line ...
********** ERROR **********
ERROR: syntax error at or near "FOREACH"
Does anybody know why and how to fix this?
FOREACH construct was added in 9.1. For earlier versions you can use unnest() function the following way:
CREATE FUNCTION a(tab varchar[]) RETURNS void AS
$$
DECLARE
b varchar(20);
BEGIN
FOR b IN SELECT unnest(tab)
LOOP
INSERT INTO x(c) VALUES (b);
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
Since PostgreSQL 9.1 there is also a built-in way to loop through array slices:
FOREACH x SLICE 1 IN ARRAY $1
LOOP
RAISE NOTICE 'row = %', x;
END LOOP;
Where x must be a matching array type and ...
The SLICE value must be an integer constant not larger than the number of dimensions of the array
For 1-dimensional arrays just omit the SLICE part and x can be a simple type like you display in your question.
I want to add one thing, and that is that unnest unnests all levels of an array:
select * from unnest(ARRAY[ARRAY[1,2,3],Array[5,6,7]]);
unnest
--------
1
2
3
5
6
7
(6 rows)
If you want to loop through one level of a multi-dimensional array, you should loop through the following instead
FOR out_count IN
array_lower(in_transactions, 1) ..
array_upper(in_transactions, 1)
LOOP
-- Fill the bulk payments table
INSERT INTO bulk_payments_in(id, amount)
VALUES (in_transactions[out_count][1],
in_transactions[out_count][2]);
END LOOP;