Как клонировать запись в 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
с простым выражением.
У меня не хватает времени, объяснение в следующих ответах:
- Объявите переменную составного типа в PostgreSQL, используя%TYPE
- Рефакторинг функции PL/pgSQL для возврата результатов различных запросов SELECT
Asides:
- Не указывайте название языка, это идентификатор, а не строка.
- Вы действительно нуждаетесь
WITH (oids = true)
в твоей таблице? Это все еще разрешено, но в значительной степени осуждается в современных Postgres.