sql >> Databasteknik >  >> RDS >> PostgreSQL

Skärning av flera arrayer i PostgreSQL

Det närmaste en array-korsning jag kan komma på är detta:

select array_agg(e)
from (
    select unnest(a1)
    intersect
    select unnest(a2)
) as dt(e)

Detta förutsätter att a1 och a2 är endimensionella arrayer med samma typ av element. Du kan slå in det i en funktion ungefär så här:

create function array_intersect(a1 int[], a2 int[]) returns int[] as $$
declare
    ret int[];
begin
    -- The reason for the kludgy NULL handling comes later.
    if a1 is null then
        return a2;
    elseif a2 is null then
        return a1;
    end if;
    select array_agg(e) into ret
    from (
        select unnest(a1)
        intersect
        select unnest(a2)
    ) as dt(e);
    return ret;
end;
$$ language plpgsql;

Då kan du göra så här:

=> select array_intersect(ARRAY[2,4,6,8,10], ARRAY[1,2,3,4,5,6,7,8,9,10]);
 array_intersect 
-----------------
 {6,2,4,10,8}
(1 row)

Observera att detta inte garanterar någon speciell ordning i den returnerade arrayen men du kan fixa det om du bryr dig om det. Sedan kan du skapa din egen aggregatfunktion:

-- Pre-9.1
create aggregate array_intersect_agg(
    sfunc    = array_intersect,
    basetype = int[],
    stype    = int[],
    initcond = NULL
);

-- 9.1+ (AFAIK, I don't have 9.1 handy at the moment
-- see the comments below.
create aggregate array_intersect_agg(int[]) (
    sfunc = array_intersect,
    stype = int[]
);

Och nu ser vi varför array_intersect gör roliga och lite kluriga saker med NULLs. Vi behöver ett initialt värde för aggregeringen som beter sig som den universella uppsättningen och vi kan använda NULL för det (ja, det här luktar lite illa men jag kan inte komma på något bättre från mitt huvud).

När allt detta är på plats kan du göra så här:

> select * from stuff;
    a    
---------
 {1,2,3}
 {1,2,3}
 {3,4,5}
(3 rows)

> select array_intersect_agg(a) from stuff;
 array_intersect_agg 
---------------------
 {3}
(1 row)

Inte direkt enkelt eller effektivt men kanske en rimlig utgångspunkt och bättre än ingenting alls.

Användbara referenser:

  • array_agg
  • skapa aggregat
  • skapa funktion
  • PL/pgSQL
  • unnest


  1. Hur man uppdaterar primärnyckeln

  2. När jag anropar PreparedStatement.cancel() i ett JDBC-program, dödar det verkligen det i en Oracle-databas?

  3. Hur man får aktuellt datum och tid (utan tidszon) i T-SQL

  4. Analysera parameterns standardvärden med PowerShell – Del 3