developer tip

PostgreSQL의 함수 내에서 SELECT 결과를 반환하는 방법은 무엇입니까?

optionbox 2020. 9. 10. 07:42
반응형

PostgreSQL의 함수 내에서 SELECT 결과를 반환하는 방법은 무엇입니까?


PostgreSQL에이 함수가 있지만 쿼리 결과를 반환하는 방법을 모르겠습니다.

CREATE OR REPLACE FUNCTION wordFrequency(maxTokens INTEGER)
  RETURNS SETOF RECORD AS
$$
BEGIN
    SELECT text, count(*), 100 / maxTokens * count(*)
    FROM (
        SELECT text
    FROM token
    WHERE chartype = 'ALPHABETIC'
    LIMIT maxTokens
    ) as tokens
    GROUP BY text
    ORDER BY count DESC
END
$$
LANGUAGE plpgsql;

하지만 PostgreSQL 함수 내에서 쿼리 결과를 반환하는 방법을 모르겠습니다.

반환 유형이이어야 함을 알았 SETOF RECORD습니다. 그러나 반환 명령은 옳지 않습니다.

이를 수행하는 올바른 방법은 무엇입니까?


사용 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) 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$  LANGUAGE plpgsql;

요구:

SELECT * FROM word_frequency(123);

설명:

  • 반환 유형을 단순히 레코드로 선언하는 것보다 명시 적으로 정의하는 것이 훨씬 더 실용적입니다. 이렇게하면 모든 함수 호출에 열 정의 목록을 제공 할 필요가 없습니다. RETURNS TABLE그렇게하는 한 가지 방법입니다. 다른 것들이 있습니다. OUT매개 변수의 데이터 유형은 쿼리에서 반환 된 것과 정확히 일치해야합니다.

  • OUT매개 변수의 이름을 신중하게 선택하십시오 . 거의 모든 곳에서 기능 본문에서 볼 수 있습니다. 충돌이나 예기치 않은 결과를 방지하기 위해 동일한 이름의 열을 테이블 한정합니다. 내 예제의 모든 열에 대해 그렇게했습니다.

    그러나 매개 변수 와 동일한 이름의 열 별칭 간에 잠재적 인 이름 지정 충돌에 유의하십시오 . 이 특별한 경우 ( ) Postgres는 매개 변수에 대해 열 별칭을 사용합니다 . 하지만 다른 상황에서는 모호 할 수 있습니다. 혼동을 피할 수있는 다양한 방법이 있습니다.OUTcntRETURN QUERY SELECT ...OUT

    1. SELECT 목록에서 항목의 서수 위치를 사용하십시오 ORDER BY 2 DESC.. 예:
    2. 식을 반복합니다 ORDER BY count(*).
    3. (Not applicable here.) Set the configuration parameter plpgsql.variable_conflict or use the special command #variable_conflict error | use_variable | use_column in the function. See:
  • Don't use "text" or "count" as column names. Both are legal to use in Postgres, but "count" is a reserved word in standard SQL and a basic function name and "text" is a basic data type. Can lead to confusing errors. I use txt and cnt in my examples.

  • Added a missing ; and corrected a syntax error in the header. (_max_tokens int), not (int maxTokens) - type after name.

  • While working with integer division, it's better to multiply first and divide later, to minimize the rounding error. Even better: work with numeric (or a floating point type). See below.

Alternative

This is what I think your query should actually look like (calculating a relative share per token):

CREATE OR REPLACE FUNCTION word_frequency(_max_tokens int)
  RETURNS TABLE (txt            text
               , abs_cnt        bigint
               , relative_share numeric) 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$  LANGUAGE plpgsql;

The expression sum(t.cnt) OVER () is a window function. You could use a CTE instead of the subquery - pretty, but a subquery is typically cheaper in simple cases like this one.

A final explicit RETURN statement is not required (but allowed) when working with OUT parameters or RETURNS TABLE (which makes implicit use of OUT parameters).

round() with two parameters only works for numeric types. count() in the subquery produces a bigint result and a sum() over this bigint produces a numeric result, thus we deal with a numeric number automatically and everything just falls into place.


Hi please check the below link

https://www.postgresql.org/docs/current/xfunc-sql.html

EX:

CREATE FUNCTION sum_n_product_with_tab (x int)
RETURNS TABLE(sum int, product int) AS $$
    SELECT $1 + tab.y, $1 * tab.y FROM tab;
$$ LANGUAGE SQL;

참고URL : https://stackoverflow.com/questions/7945932/how-to-return-result-of-a-select-inside-a-function-in-postgresql

반응형