sql >> Database >  >> RDS >> PostgreSQL

Retourneer rijen die overeenkomen met elementen van invoerarray in plpgsql-functie

Dit werkt:

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;

Bel:

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

Of (update - voorbeeld met dollaraanhalingstekens):

SELECT * FROM avg_purchases($x${foo,Bar,baz,"}weird_name'$$"}$x$);
  • Meer over het citeren van letterlijke tekenreeksen:
    Voeg tekst in met enkele aanhalingstekens in PostgreSQL

  • Je hebt hier geen dynamische SQL nodig.

  • Terwijl je kunt wikkel het in een plpgsql-functie (wat handig kan zijn), een eenvoudige SQL-functie doet het werk prima.

  • U heeft niet-overeenkomende typen .

    • het resultaat van avg() kan numeric zijn om een ​​nauwkeurig resultaat vast te houden. Ik cast naar float8 om het te laten werken, wat slechts een alias is voor double precision (je kunt beide gebruiken). Als je perfecte precisie nodig hebt, gebruik dan numeric in plaats daarvan.
    • Sinds je GROUP BY last_name je wilt een platte text OUT-parameter in plaats van text[] .

VARIADIC

Een array is een handig type invoer. Als het voor uw klant gemakkelijker is, kunt u ook een VARIADIC . gebruiken invoerparameter waarmee de array kan worden doorgegeven als een lijst met elementen :

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;

Oproep:

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

Of (met dollaraanhaling):

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

Houd er rekening mee dat standaard Postgres slechts een maximaal 100 elementen toestaat . Dit wordt tijdens het compileren bepaald door de vooraf ingestelde optie:

max_function_args (integer)

Rapporteert het maximum aantal functieargumenten. Het wordt bepaald door de waarde van FUNC_MAX_ARGS bij het bouwen van de server. De standaardwaarde is 100 argumenten.

Je kunt het nog steeds aanroepen met array-notatie als het wordt voorafgegaan door het trefwoord VARIADIC :

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

Voor grotere arrays (100+), zou ik ook unnest() . gebruiken in een subquery en JOIN ernaartoe, wat beter schaalt:

  • Een Postgres-query optimaliseren met een grote IN



  1. Een SQL-query om een ​​string te selecteren tussen twee bekende strings

  2. Slow bulk insert voor tafel met veel indexen

  3. Best practices:.NET:Hoe kan ik PK retourneren tegen een Oracle-database?

  4. Hoe te bestellen op datum in T-SQL