在Postgres数组中查找重复项,并另存为不同的字段

时间:2017-11-16 22:53:48

标签: postgresql

My Postgres表架构有两个字段:

items,其中包含(整数)项ID的数组。如果数组中的相同ID 两次,则将其视为主要项目。

primary_items,我刚刚添加到架构中的另一个(整数)项ID数组,因此它在所有行中当前为空。

我需要做的是:对于每一行,检查items中是否有重复的ID,如果是,请将每个重复的ID中的一个放入primary_items字段。

有关如何使用查询处理此问题的任何想法?理想情况下,我不必编写帮助程序(Nodejs)来执行此操作,但如果需要,我可以。

示例:

当前

documents_table
items          primary_items
------------   -----------
{1, 2, 2, 4}    {}
{1, 2, 3}       {}
{3, 3}          {}
{5, 4, 5, 4}    {}

所需

documents_table
items          primary_items
------------   -----------
{1, 2, 2, 4}    {2}
{1, 2, 3}       {}
{3, 3}          {3}
{5, 4, 5, 4}    {5,4}

2 个答案:

答案 0 :(得分:3)

您可以通过以下简单查询找到重复的元素:

select array_agg(item)
from (
    select item
    from unnest('{5, 4, 5, 4}'::int[]) as item
    group by item
    having count(*) > 1
) s

 array_agg 
-----------
 {4,5}
(1 row) 

在函数中使用查询:

create or replace function find_primary_items(arr anyarray)
returns anyarray language sql immutable
as $$
    select array_agg(item)
    from (
        select item
        from unnest(arr) as item
        group by item
        having count(*) > 1
    ) s
$$;

现在更新非常容易:

update documents_table
set primary_items = coalesce(find_primary_items(items), '{}')
returning *;

   items   | primary_items 
-----------+---------------
 {1,2,2,4} | {2}
 {1,2,3}   | {}
 {3,3}     | {3}
 {5,4,5,4} | {4,5}
(4 rows)

答案 1 :(得分:0)

SQL Fiddle

您可以通过计算数组中加倍的元素来实现。取消嵌套数组,并使用row_number窗口函数计算加倍的值:

https://www.postgresql.org/docs/current/static/functions-window.html

UPDATE documents_table                           -- E
SET primary_items = s.primaries
FROM (
    SELECT 
        id,
        array_agg(array_element) as primaries    -- D.2
    FROM (
        SELECT
            id,
            array_element,
            row_number() OVER (PARTITION BY id, array_element) as same_element_count  -- C
        FROM (
            SELECT 
                items as id,                     -- A
                unnest(items) as array_element   -- B
            FROM 
                documents_table
            ORDER BY 
                id, array_element
        ) s
    ) s
    WHERE same_element_count = 2                -- D.1
    GROUP BY id) s
WHERE items = s.id;

A:需要一个ID。将该数组用作ID,但最好为此添加一个ID列

B:unnest将数组扩展为每个元素一行。这是必需的,因为可以对行进行排序并将其用于进一步的窗口函数计算。

C:row_number窗口函数:分区划分行。订购后,ID中的每个值都在同一分区中。如果ID中有两次或多次相同的值,则这些值在同一分区中。 row_number计算一个分区中的元素。因此,双倍的值将获得行号'2'

D.1:过滤加倍的值

D.2:将每个ID的所有双精度值聚合到一个数组中。这将为您最后的primary_items

E:更新这些内容以计算表中的primary_items数组。