3
CREATE TABLE array_test (
  id serial primary key,
  data text[]
);

INSERT INTO array_test (data) VALUES
  ('{"one", "two"}');

-- Now I need to insert a second member of the array. My try would be the following, but the code only redefines the second member:

UPDATE array_test SET data[2] = 'three'
WHERE id = 1;
7
  • but the second member of array is two?.. so it updates it with new value - all as expected Commented Oct 23, 2017 at 12:14
  • Yes, it does update the array. I need to insert a value into it. For the result to be {"one", "three", "two"} Commented Oct 23, 2017 at 12:17
  • with auto shift? or for known array length?.. Commented Oct 23, 2017 at 12:22
  • with auto shift would be ok Commented Oct 23, 2017 at 12:23
  • :D without it solution is obvious, with it will require a bit of coding, so if the length is defined - things will be much easier Commented Oct 23, 2017 at 12:24

2 Answers 2

4

You can slice the existing array and append the new values to those slices:

update array_test
   set data = data[:1]||'three'::text||data[2:];

data[:1] selects everything up to the first element and data[2:] selects everything after (and including) the second element.

If you need this very often, it might make sense to put this into a function.

create or replace function array_set_at(p_data text[], p_pos int, p_element text)
  returns text[]
as
$$
  select p_data[:p_pos - 1]||p_element||p_data[p_pos:];
$$ 
language sql;

Then you can do it like this:

update array_test
   set data = array_set_at(data, 2, 'three');
Sign up to request clarification or add additional context in comments.

2 Comments

Is there a similar elegant way to do the same with JSON?
@ИванЗавадский: not that I am aware off. JSON arrays are not as flexible as "native" arrays.
0

I dont recal array function that would allow you auto shift, so here's some coding:

t=# begin;
BEGIN
Time: 0.117 ms
t=#  with idx(v,t) as (values(2,'three'))
t-# , u as (select case when o > v then o+1 else o end, e from array_test,idx,unnest(data) with ordinality u(e,o) where id =1)
t-# , f as (select * from u union select * from idx)
t-# , r as (select array_agg(e order by o) from f)
t-# update array_test set data = array_agg
t-# from r
t-# where id =1;
UPDATE 1
Time: 0.635 ms
t=# select * from array_test;
 id |      data
----+-----------------
  1 | {one,two,three}
(1 row)

Time: 0.207 ms
t=# end;
COMMIT
Time: 0.874 ms

CTE idx(v,t) as (values(2,'three')) is your [2] and three - value for it

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.