sql >> Databáze >  >> RDS >> PostgreSQL

Jak vrátit výsledek SELECT uvnitř funkce v PostgreSQL?

Použijte RETURN QUERY :

CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
  RETURNS TABLE (txt   text   -- also visible as OUT parameter inside function
               , cnt   bigint
               , ratio bigint)
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY
   SELECT t.txt
        , count(*) AS cnt                 -- column alias only visible inside
        , (count(*) * 100) / _max_tokens  -- I added brackets
   FROM  (
      SELECT t.txt
      FROM   token t
      WHERE  t.chartype = 'ALPHABETIC'
      LIMIT  _max_tokens
      ) t
   GROUP  BY t.txt
   ORDER  BY cnt DESC;                    -- potential ambiguity 
END
$func$;

Volejte:

SELECT * FROM word_frequency(123);

Explicitní definování návratového typu je hodně praktičtější než vrácení obecného record . Tímto způsobem nemusíte při každém volání funkce poskytovat seznam definic sloupců. RETURNS TABLE je jeden způsob, jak to udělat. Jsou i další. Datové typy OUT parametry musí přesně odpovídat tomu, co je vráceno dotazem.

Vyberte názvy pro OUT parametry pečlivě. Jsou viditelné v těle funkce téměř kdekoli. Sloupce se stejným názvem upravte podle tabulky, abyste předešli konfliktům nebo neočekávaným výsledkům. Udělal jsem to pro všechny sloupce v mém příkladu.

Všimněte si však potenciálního konfliktu názvů mezi OUT parametr cnt a alias sloupce se stejným názvem. V tomto konkrétním případě (RETURN QUERY SELECT ... ) Postgres používá alias sloupce přes OUT parametr v obou směrech. To však může být v jiných kontextech nejednoznačné. Existují různé způsoby, jak se vyhnout nejasnostem:

  1. Použijte pořadovou pozici položky v seznamu SELECT:ORDER BY 2 DESC . Příklad:
    • Vybrat první řádek v každé skupině GROUP BY?
  2. Opakujte výraz ORDER BY count(*) .
  3. (Zde nelze použít.) Nastavte konfigurační parametr plpgsql.variable_conflict nebo použijte speciální příkaz #variable_conflict error | use_variable | use_column ve funkci. Viz:
    • Konflikt pojmenování mezi parametrem funkce a výsledkem JOIN s klauzulí USING

Jako názvy sloupců nepoužívejte „text“ nebo „počet“. Obojí je legální pro použití v Postgresu, ale „počet“ je rezervované slovo ve standardním SQL a základní název funkce a "text" je základní datový typ. Může vést k matoucím chybám. Používám txt a cnt v mých příkladech možná budete chtít explicitnější jména.

Přidán chybějící ; a opravena syntaktická chyba v záhlaví. (_max_tokens int) , nikoli (int maxTokens) - typ za jméno .

Při práci s celočíselným dělením je lepší nejprve násobit a později dělit, aby se minimalizovala chyba zaokrouhlování. Nebo pracujte s numeric nebo typu s plovoucí desetinnou čárkou. Viz níže.

Alternativa

Tohle si myslím váš dotaz by měl ve skutečnosti vypadat (výpočet relativního podílu na token ):

CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
  RETURNS TABLE (txt            text
               , abs_cnt        bigint
               , relative_share numeric)
  LANGUAGE plpgsql AS
$func$
BEGIN
   RETURN QUERY
   SELECT t.txt, t.cnt
        , round((t.cnt * 100) / (sum(t.cnt) OVER ()), 2)  -- AS relative_share
   FROM  (
      SELECT t.txt, count(*) AS cnt
      FROM   token t
      WHERE  t.chartype = 'ALPHABETIC'
      GROUP  BY t.txt
      ORDER  BY cnt DESC
      LIMIT  _max_tokens
      ) t
   ORDER  BY t.cnt DESC;
END
$func$;

Výraz sum(t.cnt) OVER () je funkce okna. Mohli byste místo poddotazu použijte CTE. Pěkné, ale dílčí dotaz je v jednoduchých případech, jako je tento, obvykle levnější (většinou před Postgres 12).

Poslední explicitní RETURN prohlášení není vyžadováno (ale povoleno) při práci s OUT parametry nebo RETURNS TABLE (což implicitně využívá OUT parametry).

round() se dvěma parametry funguje pouze pro numeric typy. count() v poddotazu vytvoří bigint výsledek a sum() přes tento bigint vytvoří numeric výsledkem je tedy numeric číslo automaticky a vše zapadne na své místo.



  1. Propojení nebo import dat ze Salesforce

  2. Vraťte krátký název měsíce z data v Oracle

  3. Vyberte data prostřednictvím funkce s hodnotou tabulky na serveru SQL Server

  4. PostgreSQL řádek do sloupců