PL / pgSQL에서 여러 행의 레코드를 반환하는 방법


14

RECORD 데이터 형식을 사용하여 여러 레코드를 반환하려고하는데 RECORD에 추가 하고이 RECORD에 각 반복마다 새로운 값을 추가 / 추가 할 수있는 방법이 있습니까?

즉, 루프가 끝나면 행 세트가 rec되도록 추가하고 싶습니다 rec.이 기능은 함수 끝에서 반환 할 수 있습니다. 현재, 나는 이것을하고있다-

SELECT temp_table.col1, temp_table.col2, temp_table.col3
      INTO rec
      FROM temp_table
      WHERE temp_table.col3 = false;

내 전체 코드는 다음과 같습니다.

CREATE OR REPLACE FUNCTION validation()
  RETURNS RECORD AS $$
DECLARE
        rec RECORD;
        temp_row RECORD;
BEGIN

  CREATE TEMPORARY TABLE temp_table (col1 TEXT, col2 INTEGER, col3 BOOLEAN) ON COMMIT DROP;

  FOR temp_row IN SELECT * FROM staging.validation
  LOOP

    RAISE NOTICE 'sql: %', temp_row.sql;

    EXECUTE format('INSERT INTO temp_table %s', temp_row.sql);

    IF (SELECT DISTINCT temp_table.col3 FROM temp_table WHERE temp_table.col3 = false)=false THEN
      RAISE NOTICE 'there is a false value';

      SELECT temp_table.col1, temp_table.col2, temp_table.col3
      INTO rec
      FROM temp_table
      WHERE temp_table.col3 = false;
    END IF;


  END LOOP;
  RETURN rec;
END; $$
LANGUAGE plpgsql;

이후의 전류 출력 SELECT validation();

validation
(crea_ddf,8095,f)

원하는 출력

validation
(crea_ddf,8095,f)
(some_source_system,some_count,f)
(some_other_source_system,some_count,f)
(.....)

@EvanCarroll 안녕 에반, 그게 내 질문인데, 누군가가 여기에서 그것을 놓친 경우를 대비하여 저도 게시했습니다.
hky404

당신이 무엇을하려고하는지 잘 모르겠습니다. 조금 더 설명해 주시겠습니까?
Evan Carroll

1
@ hky404 : 교차 게시하지 마십시오; 노력의 중복을 유발합니다.
Martijn Pieters

답변:


14

함수 SETOF RECORD는 다음 RECORD과 같이 대신 을 반환하고 하나 RETURN NEXT대신 행당 하나 를 가져와야합니다 RETURN.

CREATE FUNCTION test() RETURNS SETOF RECORD AS $$
DECLARE
 rec record;
BEGIN
  select 1,2 into rec;
  return next rec;

  select 3,4 into rec;
  return next rec;
END $$ language plpgsql;

방문객:

=> test ()에서 *를 x (a int, b int)로 선택하십시오.
 | 비
--- + ---
 1 | 2
 3 | 4
(2 행)

SQL은 강력하고 정적으로 유형이 지정되므로 RECORD의사 유형은 작업하기가 어렵습니다. 익명 유형 또는 영구 이름이 지정된 유형
TABLE(...)구문 과 함께 각 열의 이름과 유형에 대한 전체 정의가있는 복합 유형을 처음부터 바로 사용하는 것이 종종 성가신 일이 아닙니다 CREATE TYPE.


8

함수에서 여러 레코드를 반환 하려면 setof recordand를 사용하십시오 return next rec.

create or replace function test_function()
    returns setof record 
    language plpgsql as $$
declare
    rec record;
begin
    for rec in
        select i, format('str%s', i), i/2*2 = i
        from generate_series(1, 3) i
    loop
        return next rec;
    end loop;
end $$;

이러한 함수는 FROM 절에서 열 정의 목록과 함께 호출되어야합니다.

select test_function(); -- NO

ERROR:  set-valued function called in context that cannot accept a set  

select * from test_function();  -- NO

ERROR:  a column definition list is required for functions returning "record"

select * from test_function() as (id int, str text, is_even boolean);

 id | str  | is_even 
----+------+---------
  1 | str1 | f
  2 | str2 | t
  3 | str3 | f
(3 rows)

더 나은 옵션을 사용하는 것입니다 returns table(...)return query:

drop function if exists test_function();
create or replace function test_function()
    returns table (id int, str text, is_even boolean)
    language plpgsql as $$
begin
    return query
        select i, format('str%s', i), i/2*2 = i
        from generate_series(1, 3) i;
    -- you can use return query multiple times
    -- or assign values to columns
    -- and return the row:
    id = 100;
    str = 'extra';
    is_even = true;
    return next; -- without a parameter
end $$;

용법:

select test_function(); -- possible but rather impractical

 test_function 
---------------
 (1,str1,f)
 (2,str2,t)
 (3,str3,f)
 (100,extra,t)
(4 rows)

select * from test_function();

 id  |  str  | is_even 
-----+-------+---------
   1 | str1  | f
   2 | str2  | t
   3 | str3  | f
 100 | extra | t
(4 rows)

1

이것은 붉은 깃발입니다 ..

  1. 당신은 테이블이 validation있습니다.
  2. 행을 임시 테이블로 이동합니다 staging.
  3. temp_table.col3IS FALSE 가있는 행 은 사용자에게 반환합니다.
  4. 해당 열이 false 인 지정된 테이블 목록의 다른 행과 함께.
  5. 그런 다음 임시 테이블을 삭제합니다 (커밋시)

그냥하세요 ..

WITH t AS ( SELECT true AS runthis FROM staging.validation WHERE col3 IS FALSE )
SELECT *
FROM staging.validation
WHERE t.runthis && col3 = 3
UNION ALL 
  SELECT *
  FROM some_source_system
  WHERE t.runthis && some_source_system.col3 = 3
UNION ALL 
  SELECT *
  FROM some_other_source_system
  WHERE t.runthis && some_other_source_system.col3 = 3;

당신도에 그것을 넣을 수 있습니다 VIEW당신이 원하는 경우

부수적으로

SELECT DISTINCT temp_table.col3
FROM temp_table
WHERE temp_table.col3 = false

여기서 무엇을 DISTINCT합니까? 하나만 제한하십시오. 사실, 나는 이것이 더 깨끗하다고 ​​주장합니다.

SELECT true
FROM temp_table
WHERE temp_table.col3 = false
LIMIT 1;

그럼 당신은 이상한 필요하지 않습니다 = false ) = FALSE

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.