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

Gibt Zeilen zurück, die mit Elementen des Eingabearrays in der plpgsql-Funktion übereinstimmen

Das funktioniert:

CREATE OR REPLACE FUNCTION avg_purchases(last_names text[] = '{}')
  RETURNS TABLE(last_name text, avg_purchase_size float8) AS
$func$
   SELECT last_name, AVG(purchase_size)::float8
   FROM   purchases
   WHERE  last_name = ANY($1)
   GROUP  BY last_name
$func$  LANGUAGE sql;

Aufruf:

SELECT * FROM avg_purchases('{foo,Bar,baz,"}weird_name''$$"}');

Oder (aktualisieren - Beispiel mit Dollar-Quote):

SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
  • Weitere Informationen zum Zitieren von Zeichenfolgenliteralen:
    Text mit einfachen Anführungszeichen in PostgreSQL einfügen

  • Sie brauchen hier kein dynamisches SQL.

  • Solange Sie können packen Sie es in eine plpgsql-Funktion (was nützlich sein kann), eine einfache SQL-Funktion erledigt die Arbeit gut.

  • Sie haben nicht übereinstimmende Typen .

    • das Ergebnis von avg() kann numeric sein um ein genaues Ergebnis zu halten. Ich caste zu float8 damit es funktioniert, was nur ein Alias ​​für double precision ist (Sie können beides verwenden). Wenn Sie absolute Genauigkeit benötigen, verwenden Sie numeric stattdessen.
    • Da Sie GROUP BY last_name Sie möchten einen einfachen text OUT-Parameter anstelle von text[] .

VARIADIC

Ein Array ist ein nützlicher Eingabetyp. Wenn es für Ihren Kunden einfacher ist, können Sie auch einen VARIADIC verwenden Eingabeparameter, der es erlaubt, das Array als Liste von Elementen zu übergeben :

CREATE OR REPLACE FUNCTION avg_purchases(VARIADIC last_names text[] = '{}')
  RETURNS TABLE(last_name text, avg_purchase_size float8) AS
$func$
   SELECT last_name, AVG(purchase_size)::float8
   FROM   purchases
   JOIN  (SELECT unnest($1)) t(last_name) USING (last_name)
   GROUP  BY last_name
$func$  LANGUAGE sql;

Aufruf:

SELECT * FROM avg_purchases('foo', 'Bar', 'baz', '"}weird_name''$$"}');

Oder (mit Anführungszeichen in Dollar):

SELECT * FROM avg_purchases('foo', 'Bar', 'baz', $y$'"}weird_name'$$"}$y$);

Beachten Sie, dass Standard-Postgres nur maximal 100 Elemente zulässt . Dies wird zur Kompilierzeit durch die voreingestellte Option bestimmt:

max_function_args (integer)

Meldet die maximale Anzahl von Funktionsargumenten. Er wird durch den Wert von FUNC_MAX_ARGS bestimmt beim Aufbau des Servers. Der Standardwert ist 100 Argumente.

Sie können es immer noch in Array-Notation aufrufen, wenn das Schlüsselwort VARIADIC vorangestellt ist :

SELECT * FROM avg_purchases(VARIADIC '{1,2,3, ... 99,100,101}');

Für größere Arrays (100+) würde ich auch unnest() verwenden in einer Unterabfrage und JOIN dazu, was tendenziell besser skaliert:

  • Optimieren einer Postgres-Abfrage mit einem großen IN