2014-09-10 6 views
1

쿼리를 반복하면서 다음 루프의 실제 레코드를 유지하므로 인접한 두 행을 비교할 수 있습니다.PostgreSQL에서 RECORD를 복제하는 방법

CREATE OR REPLACE FUNCTION public.test() 
    RETURNS void AS 
$body$ 
    DECLARE 
     previous RECORD; 
     actual RECORD; 
     query TEXT; 
     isdistinct BOOLEAN; 
     tablename VARCHAR; 
     columnname VARCHAR; 
     firstrow BOOLEAN DEFAULT TRUE; 
    BEGIN 
     tablename = 'naplo.esemeny'; 
     columnname = 'esemeny_id'; 
     query = 'SELECT * FROM ' || tablename || ' LIMIT 2'; 
     FOR actual IN EXECUTE query LOOP 
     --do stuff 
     --save previous record 
     IF NOT firstrow THEN 
      EXECUTE 'SELECT ($1).' || columnname || ' IS DISTINCT FROM ($2).' || columnname 
      INTO isdistinct USING previous, actual; 
      RAISE NOTICE 'previous: %', previous.esemeny_id; 
      RAISE NOTICE 'actual: %', actual.esemeny_id;   
      RAISE NOTICE 'isdistinct: %', isdistinct; 
     ELSE 
      firstrow = false;   
     END IF; 
     previous = actual; 
     END LOOP; 
     RETURN; 
    END; 
$body$ 
LANGUAGE 'plpgsql' 
VOLATILE 
CALLED ON NULL INPUT 
SECURITY INVOKER 
COST 100; 

표 :

CREATE TABLE naplo.esemeny (
    esemeny_id SERIAL, 
    felhasznalo_id VARCHAR DEFAULT "current_user"() NOT NULL, 
    kotesszam VARCHAR(10), 
    idegen_azonosito INTEGER, 
    esemenytipus_id VARCHAR(10), 
    letrehozva TIMESTAMP WITHOUT TIME ZONE DEFAULT now() NOT NULL, 
    szoveg VARCHAR, 
    munkalap_id VARCHAR(13), 
    ajanlat_id INTEGER, 
    CONSTRAINT esemeny_pkey PRIMARY KEY(esemeny_id), 
    CONSTRAINT esemeny_fk_esemenytipus FOREIGN KEY (esemenytipus_id) 
    REFERENCES naplo.esemenytipus(esemenytipus_id) 
    ON DELETE RESTRICT 
    ON UPDATE RESTRICT 
    NOT DEFERRABLE 
) 
WITH (oids = true); 

위의 코드가 작동하지 않습니다, 다음과 같은 오류 메시지가 발생합니다 : 나는 무엇을

ERROR: could not identify column "esemeny_id" in record data type 
LINE 1: SELECT ($1).esemeny_id IS DISTINCT FROM ($2).esemeny_id 
       ^
QUERY: SELECT ($1).esemeny_id IS DISTINCT FROM ($2).esemeny_id 
CONTEXT: PL/pgSQL function "test" line 18 at EXECUTE statement 
LOG: duration: 0.000 ms statement: SET DateStyle TO 'ISO' 

를 놓친 거지?

면책 조항 : 코드가 너무 이해하지 못한다는 것을 알고 있으며, 문제를 시연 할 수 있도록 작성했습니다.

+0

이 데이터 형식에는 해당 열이 없다는 메시지가 표시됩니다. 그게 사실이야? 아마도 열 이름이'id'일까요? – Ashalynd

+0

** 함수 헤더 ** (반환 형식 및 언어 선언 포함)이 없습니다. 나는 이것을 두세 번 보았고, 사람들이이 기능의 필수적인 ** 부분을 찢어 버리는 것이 현명하고 (또는 심지어 받아 들일 수 있다고) 생각하게 만드는 것이 무엇인지 궁금해하고 있습니다. 질문을 수정하십시오. –

+0

해당 열 이름이 존재합니다. – belidzs

답변

2

귀하의 최종 목표를 실제로 설명하지 않았기 때문에 귀하의 질문에 직접 답변하지 않으므로 전혀 사용하지 못할 수도 있습니다.

: 최종 목표는 이전 행의 같은 컬럼의 값으로 현재 행의 열 값을 비교할 수하는 경우

, 그럼 당신은 윈도우 쿼리를 사용하여 오프 훨씬 더 좋을 수도

SELECT actual, previous 
FROM (
    SELECT mycolumn AS actual, 
     lag(mycolumn) OVER() AS previous 
    FROM mytable 
    ORDER BY somecriteria 
) as q 
WHERE previous IS NOT NULL 
    AND actual IS DISTINCT FROM previous 

이 예제는 현재 행이 이전 행과 다른 행을 인쇄합니다.

ORDER BY 절을 추가했음을 주목하십시오. 주문을 지정하지 않고 "이전 행"에 대해 말하면 이해가되지 않습니다. 그렇지 않으면 임의의 결과가 발생합니다.

이것은 PlPgSQL이 아닌 일반 SQL이지만 동적으로 쿼리를 생성하려는 경우 함수로 래핑 할 수 있는지 여부를 나타냅니다.

+0

나는 데이터 구조를 포함하는 기본 테이블이 있습니다. 나는 두 개의 자손 : 활성 및 아카이브 데이터가 있습니다. 행이 변경 될 때마다 원본 복사본이 아카이브에 삽입됩니다 (타임 스탬프와 사용자 이름 포함). 이렇게하면 기본 테이블에 레코드의 모든 버전이 있습니다 (하위 항목의 데이터를 집계하므로). 내 목표는 관계 이름과 키 값을 취하는 함수를 작성한 다음 각 변경 사항을 타임 스탬프, 사용자, 영향을받는 열, 이전 값 및 새 값으로 별도의 행으로 반환하는 것입니다. 당신의 생각은 좋은 것입니다, 나는 구현하려고 시도합니다 – belidzs

1

저는 실제 문제에 대한 더 나은 해결책이 있다고 확신합니다. 그러나 질문에 답하기 위해 다음과 같은 다형성 유형의 솔루션이 있습니다.

주된 문제점은 잘 알려진 복합 유형이 필요하다는 것입니다. 익명 레코드의 구조는 할당 될 때까지 정의되지 않습니다.

CREATE OR REPLACE FUNCTION public.test (actual anyelement, _col text 
             , OUT previous anyelement) AS 
$func$ 
DECLARE 
    isdistinct bool; 
BEGIN 
    FOR actual IN 
     EXECUTE format('SELECT * FROM %s LIMIT 3', pg_typeof(actual)) 
    LOOP 
     EXECUTE format('SELECT ($1).%1$I IS DISTINCT FROM ($2).%1$I', _col) 
     INTO isdistinct 
     USING previous, actual; 

     RAISE NOTICE 'previous: %; actual: %; isdistinct: %' 
        , previous, actual, isdistinct; 

     previous := actual; 
    END LOOP; 

    previous := NULL; -- reset dummy output (optional) 
END 
$func$ LANGUAGE plpgsql; 

전화 :

SELECT public.test(NULL::naplo.esemeny, 'esemeny_id') 

는 다형성 복합 유형 (적어도 나는 반복적으로 실패)에 추가 변수를 선언하는 것은 불가능하기 때문에 내가 OUT 매개 변수를 남용하고있다.

열 이름이 안정되면 두 번째 EXECUTE을 간단한 표현식으로 바꿀 수 있습니다.

내가 시간이이 관련 답변에 대한 설명 실행하고 있습니다 :

잡담을 :

  • 언어 이름을 인용하지 마십시오, 식별자가 아니라 문자열입니다.
  • 테이블에 WITH (oids = true)가 정말로 필요합니까? 이것은 여전히 ​​허용되지만, 근대 Postgres에서는 거의 사용되지 않습니다.
+0

이것 역시 효과가 있습니다 만, 다른 답변은 더 우아하기 때문에 받아 들였습니다. 언어 이름과'WITH (oids = true) '문은 도구에 의해 자동으로 생성되었으므로 프로덕션에 포함되지 않습니다. , 지적을위한 감사합니다! – belidzs

+0

@belidzs : plpgsql의 취약한 부분에 해당하는 실제 질문에 대한 해결책을 제공하는 답을 추가했습니다. 일반적인 SQL의 창 함수로 문제를 해결할 수 있다면, 꼭 * 할 *. –