PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да върна резултат от SELECT вътре във функция в PostgreSQL?

Използвайте 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$;

Обадете се:

SELECT * FROM word_frequency(123);

Изричното дефиниране на типа на връщане е много по-практично от връщането на общ record . По този начин не е нужно да предоставяте списък с дефиниции на колони с всяко извикване на функция. RETURNS TABLE е един от начините да направите това. Има и други. Типове данни OUT параметрите трябва да съвпадат точно с това, което се връща от заявката.

Изберете имена за OUT параметри внимателно. Те са видими в тялото на функцията почти навсякъде. Квалифицирайте колони със същото име, за да избегнете конфликти или неочаквани резултати. Направих това за всички колони в моя пример.

Но обърнете внимание на потенциалния конфликт при именуване между OUT параметър cnt и псевдоним на колона със същото име. В този конкретен случай (RETURN QUERY SELECT ... ) Postgres използва псевдонима на колоната над OUT параметър така или иначе. Това обаче може да бъде двусмислено в други контексти. Има различни начини да избегнете объркване:

  1. Използвайте подредната позиция на елемента в списъка SELECT:ORDER BY 2 DESC . Пример:
    • Изберете ли първия ред във всяка група GROUP BY?
  2. Повторете израза ORDER BY count(*) .
  3. (Не е приложимо тук.) Задайте конфигурационния параметър plpgsql.variable_conflict или използвайте специалната команда #variable_conflict error | use_variable | use_column във функцията. Вижте:
    • Конфликт на именуване между параметър на функцията и резултат от JOIN с клауза USING

Не използвайте "текст" или "брой" като имена на колони. И двете са законни за използване в Postgres, но "брой" е запазена дума в стандартен SQL и име на основна функция и "текст" е основен тип данни. Може да доведе до объркващи грешки. Използвам txt и cnt в моите примери може да искате по-ясни имена.

Добавен липсващ ; и коригира синтактична грешка в заглавката. (_max_tokens int) , а не (int maxTokens) - тип след име .

Докато работите с целочислено деление, е по-добре първо да умножите и да разделите по-късно, за да сведете до минимум грешката при закръгляване. Или работете с numeric или тип с плаваща запетая. Вижте по-долу.

Алтернатива

Това мисля вашата заявка всъщност трябва да изглежда така (изчисляване на относителен дял на токен ):

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$;

Изразът sum(t.cnt) OVER () е функция на прозореца. Вие можете използвайте CTE вместо подзаявката. Хубаво, но подзаявката обикновено е по-евтина в прости случаи като този (предимно преди Postgres 12).

Последно изрично RETURN изявлението е не задължително (но разрешено) при работа с OUT параметри или RETURNS TABLE (което имплицитно използва OUT параметри).

round() с два параметъра работи само за numeric видове. count() в подзаявката произвежда bigint резултат и sum() над този bigint произвежда numeric резултат, така че имаме работа с numeric номер автоматично и всичко просто си идва на мястото.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL заявка за броене/групиране по дни и показване на дни без данни

  2. В PostgreSQL, как да вмъкна данни с команда COPY?

  3. Внедряване на Django + Python 3 + PostgreSQL към AWS Elastic Beanstalk

  4. Как да накарам моята база данни postgresql да използва съпоставяне без значение за главни букви?

  5. Как да защитите своята PostgreSQL база данни - 10 съвета