2014-09-10 57 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 2014-09-10 23:39:32

+0

**函数头**(包括返回类型和语言声明)缺失。我已经看了几次,真的很想知道是什么让人们认为这个**必不可少的**部分是明智的(或者甚至是可以接受的)。请编辑你的问题。 – 2014-09-11 21:42:08

+0

存在问题的列名称。 – belidzs 2014-09-12 06:23:05

回答

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,但是如果您想要动态生成查询,可以将它封装在函数中。

+0

我有一个基表,它包含数据的结构。我有两个后代:主动和归档数据。每当一行更改时,原件的副本将被插入到存档中(包含时间戳和用户名)。这样基表就拥有其记录的每个版本(因为它聚合了后代的数据)。我的目标是编写一个函数,该函数采用关系的名称和键值,然后将每个更改作为单独的行返回:时间戳,用户,受影响的列,旧值和新值。你的想法是一个好主意,我会尝试实施 – belidzs 2014-09-12 15:55:31

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 2014-09-18 20:35:20

+0

@belidzs:我添加了一个答案,为实际问题提供了一个解决方案,这个问题碰到了plpgsql的一个弱点。如果你可以用普通的SQL来解决你的问题,那么可以用*表示*。 – 2014-09-18 22:36:09