sql >> Database >  >> RDS >> PostgreSQL

Doe mee met 2 sets op basis van standaardvolgorde

Nu, om de echte . te beantwoorden vraag die werd onthuld in opmerkingen, die zoiets lijkt te zijn als:

Er zijn een aantal manieren om dit aan te pakken:

  • Als en alleen als de arrays even lang zijn, gebruik dan meerdere unnest functies in de SELECT clausule (een verouderde benadering die alleen mag worden gebruikt voor achterwaartse compatibiliteit);

  • Gebruik generate_subscripts om over de arrays te lopen;

  • Gebruik generate_series over subquery's tegen array_lower en array_upper om generate_subscripts te emuleren als u versies moet ondersteunen die te oud zijn om generate_subscripts te hebben;

  • Afgaand op de opdracht die unnest geeft tuples terug en hoopt - zoals in mijn andere antwoord en zoals hieronder weergegeven. Het zal werken, maar het is niet gegarandeerd dat het werkt in toekomstige versies.

  • Gebruik de WITH ORDINALITY functionaliteit toegevoegd in PostgreSQL 9.4 (zie ook zijn eerste bericht ) om een ​​rijnummer te krijgen voor unnest wanneer 9.4 uitkomt.

  • Gebruik multiple-array UNNEST , wat SQL-standaard is, maar die PostgreSQL ondersteunt nog niet .

Dus, stel dat we de functie arraypair . hebben met arrayparameters a en 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;

en het wordt aangeroepen als:

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

mogelijke functiedefinities zijn:

SRF-in-SELECT (verouderd)

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;

Zal bizarre en onverwachte resultaten opleveren als de arrays niet even lang zijn; zie de documentatie over set terugkerende functies en hun niet-standaard gebruik in de SELECT lijst om erachter te komen waarom en wat er precies gebeurt.

generate_subscripts

Dit is waarschijnlijk de veiligste optie:

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;

Als de arrays van ongelijke lengte zijn, zoals geschreven, retourneert het null-elementen voor de kortere, dus het werkt als een volledige outer join. Keer de betekenis van de behuizing om om een ​​innerlijk-join-achtig effect te krijgen. De functie gaat ervan uit dat de arrays eendimensionaal zijn en dat ze beginnen bij index 1. Als een volledig arrayargument NULL is, retourneert de functie NULL.

Een meer algemene versie zou worden geschreven in PL/PgSQL en zou array_ndims(a) = 1 controleren , controleer array_lower(a, 1) = 1 , test op null-arrays, enz. Dat laat ik aan u over.

Hoop op paarsgewijs rendement:

Dit werkt niet gegarandeerd, maar wel met de huidige query-uitvoerder van 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;

Ik zou overwegen om generate_subscripts te gebruiken veel veiliger.

Multi-argument unnest :

Dit moet werkt, maar niet omdat PostgreSQL's unnest accepteert (nog) geen meerdere invoerarrays:

SELECT * FROM unnest(a,b);


  1. Tijdstempel aftrekken in orakel die rare gegevens retourneert

  2. Hoe te testen of Ci met succes gegevens heeft ingevoegd?

  3. Verschillende tabellen samenvoegen op basis van kolomwaarde

  4. SQL Server RAISERROR-instructie met eenvoudige voorbeelden