Updating values in PostgreSQL array - sql

I have some columns in PostgreSQL database that are array. I want to add a new value (in UPDATE) in it if the value don't exists, otherwise, don't add anytihing. I don't want to overwrite the current value of the array, but only add the element to it.
Is possible do this in a query or I need to do this inside a function? I'm using PostgreSQL.

This should be as simple as this example for an integer array (integer[]):
UPDATE tbl SET col = col || 5
WHERE (5 = ANY(col)) IS NOT TRUE;
A WHERE clause like:
WHERE 5 <> ALL(col)
would also catch the case of an empty array '{}'::int[], but fail if a NULL value appears as element of the array.
If your arrays never contain NULL as element, consider actual array operators, possibly supported by a GIN index.
UPDATE tbl SET col = col || 5
WHERE NOT col #> '{5}';
See:
Check if value exists in Postgres array
Can PostgreSQL index array columns?

Related

Checking to see if array field is null or empty?

In snowflake, how can I filter for null or empty array fields in a column?
Column has an empty [] or string of values in that bracket, tried using array_size(column_name, 1) > 0 but array_size does not function,
Thanks
Are you trying to filter them in or out?
Either way the array_size should work. although there's no second argument
where column_name is not null and array_size(column_name) != 0 worked for me
If you're specifically looking to filter to the records that have an empty array, this approach works too, although it's a little odd.
where column_name = array_construct()
Edit: It seems like your issue is that your column is a string. There's a few ways to work around this
Change your column's datatype to a variant or array
Parse your column before using array functions array_size(TRY_PARSE_JSON(column_name)) != 0
Compare to a string instead column_name is not null and column_name != '[]'
If the column is string, it has to be parsed first:
SELECT *
FROM tab
WHERE ARRAY_SIZE(TRY_PARSE_JSON(column_name)) > 0;
-- excluding NULLs/empty arrays

PSQL Update a jsonb property with a concatenation to its current value

Lets assume I have a column X which is of jsonb type. X has json's of structure
{"y":"some value","z":"some more values"}.
Now what I need to achieve is that I want to append "!!!!" to the end of all z properties. The append operation should update the existing records
Use the ->> operator to get the value of z as text and the || operator to append the other string. Convert the result to jsonb with to_jsonb() and assign it to z with jsonb_set().
SELECT jsonb_set(x, '{z}', to_jsonb(x->>'z' || '!!!!'))
FROM elbat;
More info: "9.15. JSON Functions and Operators"
This did the trick
UPDATE thetable set x=jsonb_set(x, '{z}', to_jsonb(x->>'z' || '!!!!'), true)

Dynamic Case statement in postgres

I am having two arrays. Both array calculated from functions so both arrays are dynamic but length of both arrays will be same.
a1= ARRAY[1,2,3];
a2= ARRAY[10,20,30];
Now I want to update my table something like this
UPDATE TABLE SET data= CASE
data=a1[1] then a2[1]
data=a1[2] then a2[2]
data=a1[3] then a2[3]END
where id=1;
I tried with adding loop inside CASE but it is not working .
You can make use of array_position to find the matching index in array 1, and query array 2 using this index:
UPDATE TABLE
SET data = a2[array_position(a1, data)]
WHERE id = 1;
http://rextester.com/CBJ37276

Check subset using either string or array in Impala

I have a table like this
col
-----
A,B
The col could be string with comma or array. I have flexibility on the storage.
How to check of col is a subset of either another string or array variable? For example:
B,A --> TRUE (order doesn't matter)
A,D,B --> TRUE (other item in between)
A,D,C --> FALSE (missing B)
I have flexibility on the type. The variable is something I cannot store in a table.
Please let me know if you have any suggestion for Impala only (no Hive).
Thanks
A not pretty method, but perhaps a starting point...
Assuming a table with a unique identifier column id and an array<string> column col, and a string variable with ',' as a separator (and no occurrences of escaped '\,')...
SELECT
yourTable.id
FROM
yourTable,
yourTable.col
GROUP BY
yourTable.id
HAVING
COUNT(DISTINCT CASE WHEN find_in_set(col.item, ${VAR:yourString}) > 0 THEN col.item END)
=
LENGTH(regexp_replace(${VAR:yourString},'[^,]',''))+1
Basically...
Expand the arrays in your table, to one row per array item.
Check if each item exists in your string.
Aggregate back up to count how many of the items were found in the string.
Check that the number of items found is the same as the number of items in the string
The COUNT(DISTINCT <CASE>) copes with arrays like {'a', 'a', 'b', 'b'}.
Without expanding the string to an array or table (which I don't know how to do) you're dependent on the items in the string being unique. (Because I'm just counting commas in the string to find out how many items there are...)

Remove n elements from array using start and end index

I have the following table in a Postgres database:
CREATE TABLE test(
id SERIAL NOT NULL,
arr int[] NOT NULL
)
And the array contains about 500k elements.
I would like to know if there is an efficient way to update arr column by removing a set of elements from the array given the start and end index or just the number of "n first elements" to remove.
You can access individual elements or ranges of elements:
If you e.g. want to remove elements 5 to 8, you can do:
select arr[1:4]||arr[9:]
from test;
or as an update:
update test
set arr = arr[1:4]||arr[9:];
To remove the "first n elements", just use the slice after the n+1 element, e.g. to get remove the first 5 elements:
select arr[6:]
from test;
The syntax arr[6:] requires Postgres 9.6 or later, for earlier versions you need
select arr[6:cardinality(arr)]
from test;
cardinality() was introduced in 9.4, if you are using an even older version, you need:
select arr[6:array_lengt(arr,1)]
from test;
You can use slices (see 8.15.3. Accessing Arrays).
create table example
as select array[1,2,3,4,5,6,7,8] arr;
Remove first 3 elements:
select arr[4:8]
from example;
arr
-------------
{4,5,6,7,8}
(1 row)
Remove elements from 4 to 5:
select arr[1:3] || arr[6:8] as arr
from example;
arr
---------------
{1,2,3,6,7,8}
(1 row)
Remove first 5 elements if the length of the array is unknown:
select arr[6:array_length(arr,1)]
from example;
arr
---------
{6,7,8}
(1 row)