sql >> Database teknologi >  >> RDS >> PostgreSQL

PostgreSQL unnest() med elementnummer

Postgres 9.4 eller nyere

Brug WITH ORDINALITY for sæt-retur-funktioner:

Når en funktion i FROM klausul er suffikset med WITH ORDINALITY , en bigint kolonne føjes til outputtet, som starter fra 1 og stiger med 1 for hver række af funktionens output. Dette er mest nyttigt i tilfælde af sæt returnerende funktioner såsom unnest() .

I kombination med LATERAL feature i pg 9.3+, og ifølge denne tråd om pgsql-hackere, kan ovenstående forespørgsel nu skrives som:

SELECT t.id, a.elem, a.nr
FROM   tbl AS t
LEFT   JOIN LATERAL unnest(string_to_array(t.elements, ','))
                    WITH ORDINALITY AS a(elem, nr) ON TRUE;

LEFT JOIN ... ON TRUE bevarer alle rækker i den venstre tabel, selvom tabeludtrykket til højre ikke returnerer nogen rækker. Hvis det ikke er problematisk, kan du bruge dette ellers tilsvarende, mindre udførligt formular med en implicit CROSS JOIN LATERAL :

SELECT t.id, a.elem, a.nr
FROM   tbl t, unnest(string_to_array(t.elements, ',')) WITH ORDINALITY a(elem, nr);

Eller enklere, hvis den er baseret på en faktisk matrix (arr er en matrixkolonne):

SELECT t.id, a.elem, a.nr
FROM   tbl t, unnest(t.arr) WITH ORDINALITY a(elem, nr);

Eller endda med minimal syntaks:

SELECT id, a, ordinality
FROM   tbl, unnest(arr) WITH ORDINALITY a;

a er automatisk tabel og kolonne alias. Standardnavnet på den tilføjede ordinalitetskolonne er ordinality . Men det er bedre (sikkert, renere) at tilføje eksplicitte kolonnealiasser og tabelkvalificerede kolonner.

Postgres 8.4 - 9.3

Med row_number() OVER (PARTITION BY id ORDER BY elem) du får tal i henhold til sorteringsrækkefølgen, ikke ordenstallet for den oprindelige ordensposition i strengen.

Du kan simpelthen udelade ORDER BY :

SELECT *, row_number() OVER (PARTITION by id) AS nr
FROM  (SELECT id, regexp_split_to_table(elements, ',') AS elem FROM tbl) t;

Selvom dette normalt virker, og jeg aldrig har set det fejle i simple forespørgsler, hævder PostgreSQL intet vedrørende rækkefølgen af ​​rækker uden ORDER BY . Det virker tilfældigvis på grund af en implementeringsdetalje.

For at garantere ordenstal af elementer i den blank-separerede streng :

SELECT id, arr[nr] AS elem, nr
FROM  (
   SELECT *, generate_subscripts(arr, 1) AS nr
   FROM  (SELECT id, string_to_array(elements, ' ') AS arr FROM tbl) t
   ) sub;

Eller enklere, hvis den er baseret på en faktisk matrix :

SELECT id, arr[nr] AS elem, nr
FROM  (SELECT *, generate_subscripts(arr, 1) AS nr FROM tbl) t;

Relateret svar på dba.SE:

  • Hvordan bevarer man den oprindelige rækkefølge af elementer i et ikke-indlejret array?

Postgres 8.1 - 8.4

Ingen af ​​disse funktioner er tilgængelige endnu:RETURNS TABLE , generate_subscripts() , unnest() , array_length() . Men dette virker:

CREATE FUNCTION f_unnest_ord(anyarray, OUT val anyelement, OUT ordinality integer)
  RETURNS SETOF record
  LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1
 FROM   generate_series(array_lower($1,1), array_upper($1,1)) i';

Bemærk især, at array-indekset kan afvige fra ordinalpositioner af elementer. Overvej denne demo med en udvidet funktion :

CREATE FUNCTION f_unnest_ord_idx(anyarray, OUT val anyelement, OUT ordinality int, OUT idx int)
  RETURNS SETOF record
  LANGUAGE sql IMMUTABLE AS
'SELECT $1[i], i - array_lower($1,1) + 1, i
 FROM   generate_series(array_lower($1,1), array_upper($1,1)) i';

SELECT id, arr, (rec).*
FROM  (
   SELECT *, f_unnest_ord_idx(arr) AS rec
   FROM  (VALUES (1, '{a,b,c}'::text[])  --  short for: '[1:3]={a,b,c}'
               , (2, '[5:7]={a,b,c}')
               , (3, '[-9:-7]={a,b,c}')
      ) t(id, arr)
   ) sub;

 id |       arr       | val | ordinality | idx
----+-----------------+-----+------------+-----
  1 | {a,b,c}         | a   |          1 |   1
  1 | {a,b,c}         | b   |          2 |   2
  1 | {a,b,c}         | c   |          3 |   3
  2 | [5:7]={a,b,c}   | a   |          1 |   5
  2 | [5:7]={a,b,c}   | b   |          2 |   6
  2 | [5:7]={a,b,c}   | c   |          3 |   7
  3 | [-9:-7]={a,b,c} | a   |          1 |  -9
  3 | [-9:-7]={a,b,c} | b   |          2 |  -8
  3 | [-9:-7]={a,b,c} | c   |          3 |  -7

Sammenlign:

  • Normaliser array-underskrifter for 1-dimensionelle array, så de starter med 1


  1. Forslag til implementering af revisionstabeller i SQL Server?

  2. Hvordan returnerer man et array fra Java til PL/SQL?

  3. Bedømmelse af din Database Performance Monitoring Setup

  4. Sådan opretter du en offline internationaliseringsapp:Byg projektstrukturen