有条件地删除Array Field PostgreSQL中的项目

Duc*_*ong 4 sql arrays postgresql

我正在构建一种字典应用程序,我有一个用于存储以下单词的表:

id | surface_form | examples
-----------------------------------------------------------------------
 1 | sounds       | {"It sounds as though you really do believe that",
   |              |  "A different bell begins to sound midnight"}
Run Code Online (Sandbox Code Playgroud)

surface_formtype 在哪里CHARACTER VARYING,examples是一个数组字段CHARACTER VARYING

由于示例是从另一个API自动生成的,因此它可能不包含确切的"surface_form".现在我想在示例中仅保留包含确切surface_form的句子.例如,在给定的示例中,只保留第一个句子,因为它只包含sounds第二个句子sound.

问题是我陷入了如何编写查询和/或plSQL存储过程来更新examples列,以便它只有所需的句子.

kli*_*lin 6

此查询会跳过不需要的数组元素:

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) 
Run Code Online (Sandbox Code Playgroud)

用于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; 
Run Code Online (Sandbox Code Playgroud)

rextester中测试它.


小智 5

也许你必须改变表设计.这就是PostgreSQL的文档中关于数组使用的说法:

数组不是集合; 搜索特定的数组元素可能是数据库错误设计的标志.考虑为每个将成为数组元素的项使用一个单独的表.这将更容易搜索,并且可能更好地扩展到大量元素.

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


小智 2

最紧凑的解决方案(但不一定是最快的)是编写一个函数,传递一个正则表达式和一个数组,然后返回一个仅包含与正则表达式匹配的项目的新数组。

create function get_matching(p_values text[], p_pattern text)
  returns text[]
as
$$
declare
  l_result text[] := '{}'; -- make sure it's not null
  l_element text;
begin
  foreach l_element in array p_values loop

    -- adjust this condition to whatever you want
    if l_element ~ p_pattern then
      l_result := l_result || l_element;
    end if;

  end loop;
  return l_result;
end;
$$
language plpgsql;
Run Code Online (Sandbox Code Playgroud)

if条件仅是示例。您需要将其调整为您确切存储在surface_form列中的内容。也许您需要测试正则表达式的单词边界,或者一个简单的instr()就可以了 - 您的问题对此不清楚。

清理表格就变得非常简单:

update the_table
   set examples = get_matching(examples, surface_form);
Run Code Online (Sandbox Code Playgroud)

但整个方法对我来说似乎有缺陷。如果将示例存储在适当规范化的数据模型中,效率会高得多。