PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak zwrócić wynik SELECT wewnątrz funkcji w PostgreSQL?

Użyj 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$;

Zadzwoń:

SELECT * FROM word_frequency(123);

Jawne zdefiniowanie typu zwracanego to dużo bardziej praktyczne niż zwracanie ogólnego record . W ten sposób nie musisz dostarczać listy definicji kolumn przy każdym wywołaniu funkcji. RETURNS TABLE jest jednym ze sposobów na zrobienie tego. Są inni. Typy danych OUT parametry muszą dokładnie odpowiadać temu, co jest zwracane przez zapytanie.

Wybierz nazwy dla OUT parametry ostrożnie. Są one widoczne w treści funkcji niemal wszędzie. Kolumny kwalifikujące do tabeli o tej samej nazwie, aby uniknąć konfliktów lub nieoczekiwanych wyników. Zrobiłem to dla wszystkich kolumn w moim przykładzie.

Ale zwróć uwagę na potencjalny konflikt nazw między OUT parametr cnt i alias kolumny o tej samej nazwie. W tym konkretnym przypadku (RETURN QUERY SELECT ... ) Postgres używa aliasu kolumny zamiast OUT parametr w obie strony. Jednak w innych kontekstach może to być niejednoznaczne. Istnieje wiele sposobów na uniknięcie nieporozumień:

  1. Użyj pozycji porządkowej elementu na liście SELECT:ORDER BY 2 DESC . Przykład:
    • Wybrać pierwszy wiersz w każdej grupie GROUP BY?
  2. Powtórz wyrażenie ORDER BY count(*) .
  3. (Nie dotyczy tutaj.) Ustaw parametr konfiguracyjny plpgsql.variable_conflict lub użyj specjalnego polecenia #variable_conflict error | use_variable | use_column w funkcji. Zobacz:
    • Konflikt nazw między parametrem funkcji a wynikiem JOIN z klauzulą ​​USING

Nie używaj „tekstu” ani „liczba” jako nazw kolumn. Oba są legalne w Postgresie, ale „liczba” jest słowem zastrzeżonym w standardowym SQL i nazwa funkcji podstawowej i "tekst" to podstawowy typ danych. Może prowadzić do mylących błędów. Używam txt i cnt w moich przykładach możesz potrzebować bardziej wyraźnych nazw.

Dodano brakujący ; i poprawiono błąd składni w nagłówku. (_max_tokens int) , a nie (int maxTokens) - wpisz po nazwie .

Pracując z dzieleniem liczb całkowitych, lepiej najpierw pomnożyć, a później podzielić, aby zminimalizować błąd zaokrąglania. Lub pracuj z numeric lub typu zmiennoprzecinkowego. Zobacz poniżej.

Alternatywna

Tak właśnie myślę Twoje zapytanie powinno faktycznie wyglądać (obliczanie względnego udziału 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$;

Wyrażenie sum(t.cnt) OVER () to funkcja okna. możesz użyj CTE zamiast podzapytania. Ładne, ale podzapytanie jest zazwyczaj tańsze w prostych przypadkach, takich jak ten (głównie przed Postgresem 12).

Ostateczny wyraźny RETURN oświadczenie nie wymagane (ale dozwolone) podczas pracy z OUT parametry lub RETURNS TABLE (co powoduje niejawne użycie OUT parametry).

round() z dwoma parametrami działa tylko dla numeric typy. count() w podzapytaniu tworzy bigint wynik i sum() nad tym bigint tworzy numeric wynik, więc mamy do czynienia z numeric numer automatycznie i wszystko po prostu ułoży się na swoim miejscu.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak działa pg_sleep() w PostgreSQL

  2. Dołącz do czterech stołów z udziałem LEFT JOIN bez duplikatów

  3. Jak zainstalować PgBackRest

  4. Indeks tworzenia PostgreSQL

  5. Brak ograniczenia unikalności lub wykluczenia pasującego do ON CONFLICT