PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Verbinden Sie 2 Sätze basierend auf der Standardreihenfolge

Nun, um das Echte zu beantworten Frage, die in Kommentaren aufgedeckt wurde, die ungefähr so ​​aussieht:

Es gibt ein paar Möglichkeiten, dies anzugehen:

  • Wenn und nur wenn die Arrays gleich lang sind, verwenden Sie mehrfaches unnest Funktionen im SELECT -Klausel (ein veralteter Ansatz, der nur aus Gründen der Abwärtskompatibilität verwendet werden sollte);

  • Verwenden Sie generate_subscripts um die Arrays zu durchlaufen;

  • Verwenden Sie generate_series über Unterabfragen gegen array_lower und array_upper um generate_subscripts zu emulieren wenn Sie Versionen unterstützen müssen, die zu alt sind, um generate_subscripts zu haben;

  • Verlassen Sie sich auf die Reihenfolge, die unnest gibt Tupel zurück und hofft - wie in meiner anderen Antwort und wie unten gezeigt. Es wird funktionieren, aber es ist nicht garantiert, dass es in zukünftigen Versionen funktioniert.

  • Verwenden Sie den WITH ORDINALITY Funktionalität in PostgreSQL 9.4 hinzugefügt (siehe auch sein erstes Posting ). ), um eine Zeilennummer für unnest zu erhalten wenn 9.4 herauskommt.

  • Verwenden Sie UNNEST mit mehreren Arrays , der SQL-Standard ist, aber der PostgreSQL wird noch nicht unterstützt .

Angenommen, wir haben die Funktion arraypair mit Arrayparametern a und 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;

und es wird aufgerufen als:

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

mögliche Funktionsdefinitionen wären:

SRF-in-SELECT (veraltet)

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;

Führt zu bizarren und unerwarteten Ergebnissen, wenn die Arrays nicht gleich lang sind; siehe die Dokumentation zu Satzrückgabefunktionen und ihrer nicht standardmäßigen Verwendung in SELECT Liste, um zu erfahren, warum und was genau passiert.

generate_subscripts

Dies ist wahrscheinlich die sicherste Option:

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;

Wenn die Arrays von ungleicher Länge sind, werden wie geschrieben Null-Elemente für die kürzeren zurückgegeben, sodass es wie ein vollständiger äußerer Join funktioniert. Kehren Sie den Sinn des Falls um, um einen Inner-Join-ähnlichen Effekt zu erzielen. Die Funktion geht davon aus, dass die Arrays eindimensional sind und bei Index 1 beginnen. Wenn ein gesamtes Array-Argument NULL ist, gibt die Funktion NULL zurück.

Eine allgemeinere Version wäre in PL/PgSQL geschrieben und würde array_ndims(a) = 1 prüfen , überprüfen Sie array_lower(a, 1) = 1 , auf Null-Arrays testen usw. Das überlasse ich Ihnen.

Hoffnung auf paarweise Renditen:

Das funktioniert nicht garantiert, aber mit dem aktuellen Abfrage-Executor von 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;

Ich würde die Verwendung von generate_subscripts in Betracht ziehen viel sicherer.

Mehrere Argumente unnest :

Das sollte funktioniert, tut es aber nicht, weil PostgreSQL unnest akzeptiert (noch) nicht mehrere Eingabe-Arrays:

SELECT * FROM unnest(a,b);