PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Joindre 2 ensembles basés sur l'ordre par défaut

Maintenant, pour répondre au vrai question qui a été révélée dans les commentaires, qui semble être quelque chose comme :

Il existe plusieurs façons de résoudre ce problème :

  • Si et seulement si les tableaux sont de longueur égale, utilisez plusieurs unnest fonctions dans le SELECT clause (une approche obsolète qui ne doit être utilisée qu'à des fins de compatibilité descendante) ;

  • Utilisez generate_subscripts pour boucler sur les tableaux ;

  • Utilisez generate_series sur les sous-requêtes contre array_lower et array_upper pour émuler generate_subscripts si vous avez besoin de prendre en charge des versions trop anciennes pour avoir generate_subscripts;

  • S'appuyant sur l'ordre qui unnest renvoie les tuples et en espérant - comme dans mon autre réponse et comme indiqué ci-dessous. Cela fonctionnera, mais il n'est pas garanti qu'il fonctionne dans les futures versions.

  • Utilisez le WITH ORDINALITY fonctionnalité ajoutée dans PostgreSQL 9.4 (voir aussi son premier message ) pour obtenir un numéro de ligne pour unnest quand la 9.4 sortira.

  • Utiliser plusieurs tableaux UNNEST , qui est standard SQL mais qui PostgreSQL ne prend pas encore en charge .

Donc, disons que nous avons la fonction arraypair avec des paramètres tableau a et b :

CREATE OR REPLACE FUNCTION arraypair (a integer[], b text[]) 
RETURNS TABLE (col_a integer, col_b text) AS $$
  -- blah code here blah
$$ LANGUAGE whatever IMMUTABLE;

et il est invoqué comme :

SELECT * FROM arraypair( ARRAY[1,2,3,4,5,6,7], ARRAY['a','b','c','d','e','f','g'] );

les définitions de fonction possibles seraient :

SRF-dans-SELECT (obsolète)

CREATE OR REPLACE FUNCTION arraypair (a integer[], b text[])
RETURNS TABLE (col_a integer, col_b text) AS $$
    SELECT unnest(a), unnest(b);
$$ LANGUAGE sql IMMUTABLE;

Produira des résultats bizarres et inattendus si les tableaux ne sont pas égaux en longueur ; voir la documentation sur les fonctions de retour d'ensemble et leur utilisation non standard dans le SELECT liste pour savoir pourquoi et ce qui se passe exactement.

generate_subscripts

C'est probablement l'option la plus sûre :

CREATE OR REPLACE FUNCTION arraypair (a integer[], b text[])
RETURNS TABLE (col_a integer, col_b text) AS $$
    SELECT
       a[i], b[i]
    FROM generate_subscripts(CASE WHEN array_length(a,1) >= array_length(b,1) THEN a::text[] ELSE b::text[] END, 1) i;
$$ LANGUAGE sql IMMUTABLE;

Si les tableaux sont de longueur inégale, comme écrit, ils renverront des éléments nuls pour le plus court, donc cela fonctionne comme une jointure externe complète. Inversez le sens de la casse pour obtenir un effet de type jointure interne. La fonction suppose que les tableaux sont unidimensionnels et qu'ils commencent à l'index 1. Si un argument de tableau entier est NULL, la fonction renvoie NULL.

Une version plus généralisée serait écrite en PL/PgSQL et vérifierait array_ndims(a) = 1 , vérifiez array_lower(a, 1) = 1 , tester les tableaux nuls, etc. Je vous laisse faire.

En espérant des retours par paire :

Il n'est pas garanti que cela fonctionne, mais c'est le cas avec l'exécuteur de requêtes actuel de PostgreSQL :

CREATE OR REPLACE FUNCTION arraypair (a integer[], b text[])
RETURNS TABLE (col_a integer, col_b text) AS $$
 WITH
    rn_c1(rn, col) AS (
      SELECT row_number() OVER (), c1.col
      FROM unnest(a) c1(col) 
    ),
    rn_c2(rn, col) AS (
      SELECT row_number() OVER (), c2.col
      FROM unnest(b) c2(col)
    )
    SELECT
      rn_c1.col AS c1, 
      rn_c2.col AS c2
    FROM rn_c1 
    INNER JOIN rn_c2 ON (rn_c1.rn = rn_c2.rn);
$$ LANGUAGE sql IMMUTABLE;

J'envisagerais d'utiliser generate_subscripts beaucoup plus sûr.

unnest multi-arguments :

Cela devrait fonctionne, mais pas parce que unnest de PostgreSQL n'accepte pas (encore) plusieurs tableaux d'entrée :

SELECT * FROM unnest(a,b);