Как клонировать запись в PostgreSQL

Я хочу выполнить цикл запроса, но также сохранить фактическую запись для следующего цикла, чтобы я мог сравнить две соседние строки.

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'

Что мне не хватает?

Отказ от ответственности: я знаю, что код не имеет особого смысла, я только создал, чтобы я мог продемонстрировать проблему.

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 - не имеет смысла говорить о "предыдущей строке" без указания порядка, в противном случае вы получите случайные результаты.

Это обычный SQL, а не PlPgSQL, но если вы можете обернуть его в функцию, если хотите динамически генерировать запрос.

Я уверен, что есть лучшее решение для вашей проблемы. Но чтобы ответить на заданный вопрос, вот решение с полиморфными типами:

Основная проблема в том, что вам нужны хорошо известные составные типы для работы. структура анонимных записей не определена до назначения.

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 с простым выражением.

У меня не хватает времени, объяснение в следующих ответах:

Asides:

  • Не указывайте название языка, это идентификатор, а не строка.
  • Вы действительно нуждаетесь WITH (oids = true) в твоей таблице? Это все еще разрешено, но в значительной степени осуждается в современных Postgres.
Другие вопросы по тегам