Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally delete item inside an Array Field PostgreSQL

I'm building a kind of dictionary app and I have a table for storing words like below:

id | surface_form | examples
-----------------------------------------------------------------------
 1 | sounds       | {"It sounds as though you really do believe that",
   |              |  "A different bell begins to sound midnight"}

Where surface_form is of type CHARACTER VARYING and examples is an array field of CHARACTER VARYING

Since the examples are generated automatically from another API, it might not contain the exact "surface_form". Now I want to keep in examples only sentences that contain the exact surface_form. For instance, in the given example, only the first sentence is kept as it contain sounds, the second should be omitted as it only contain sound.

The problem is I got stuck in how to write a query and/or plSQL stored procedure to update the examples column so that it only has the desired sentences.

like image 946
DucCuong Avatar asked Oct 25 '16 07:10

DucCuong


People also ask

How do you delete an element from an array in SQL?

Deleting an element permanently from an array can be done using the ARRAY_DELETE function.

Can you use Delete on arrays?

Whatever you do, don't use delete to remove an item from an array. JavaScript language specifies that arrays are sparse, i.e., they can have holes in them. Using delete creates these kinds of holes. It removes an item from the array, but it doesn't update the length property.

What is Unnest in PostgreSQL?

Unnest function generates a table structure of an array in PostgreSQL. Unnest array function is beneficial in PostgreSQL for expanding the array into the set of values or converting the array into the structure of the rows. PostgreSQL offers unnest() function.


2 Answers

This query skips unwanted array elements:

select id, array_agg(example) new_examples
from a_table, unnest(examples) example
where surface_form = any(string_to_array(example, ' '))
group by id;

 id |                    new_examples                    
----+----------------------------------------------------
  1 | {"It sounds as though you really do believe that"}
(1 row) 

Use it in update:

with corrected as (
    select id, array_agg(example) new_examples
    from a_table, unnest(examples) example
    where surface_form = any(string_to_array(example, ' '))
    group by id
)
update a_table
set examples = new_examples
from corrected
where examples <> new_examples
and a_table.id = corrected.id; 

Test it in rextester.

like image 182
klin Avatar answered Oct 03 '22 02:10

klin


Maybe you have to change the table design. This is what PostgreSQL's documentation says about the use of arrays:

Arrays are not sets; searching for specific array elements can be a sign of database misdesign. Consider using a separate table with a row for each item that would be an array element. This will be easier to search, and is likely to scale better for a large number of elements.

Documentation: https://www.postgresql.org/docs/current/static/arrays.html

like image 30
2ehr Avatar answered Oct 03 '22 01:10

2ehr