1

您好,在同一张表上复制数据库记录的最简单方法是什么?

我的问题是我正在执行此操作的表有很多列,比如 100+,我不喜欢解决方案的样子。这是我所做的(这是在 plpqsql 函数中):...

1.重复记录

INSERT INTO history 
  (SELECT NEXTVAL('history_id_seq'), col_1, col_2, ... , col_100)
   FROM history
   WHERE history_id = 1234
   ORDER BY datetime DESC
   LIMIT 1)
 RETURNING
   history_id INTO new_history_id;

2.更新部分栏目

UPDATE history
SET 
    col_5 = 'test_5', 
    col_23 = 'test_23', 
    datetime = CURRENT_TIMESTAMP
WHERE history_id = new_history_id;

这是我试图解决的问题

  1. 列出所有这 100 多列看起来很蹩脚
  2. 当最终添加新列时,该功能也应该更新
  3. 在单独的数据库实例上,列顺序可能不同,这会导致函数失败

我不确定是否可以再次列出它们(解决问题 3),insert into <table> (<columns_list>) values (<query>)但查询看起来更丑陋。

我想实现像“插入”这样的东西,但这似乎是不可能的,唯一的主键约束会引发重复错误。

有什么建议么?

提前感谢您的时间。

4

2 回答 2

1

这不是很漂亮或特别优化,但有几种方法可以解决这个问题。理想情况下,您可能希望在 UPDATE 触发器中完成所有这些操作,尽管您可以实现如下所示的复制功能:

-- create source table
CREATE TABLE history (history_id serial not null primary key, col_2 int, col_3 int, col_4 int, datetime timestamptz default now());

-- add some data
INSERT INTO history (col_2, col_3, col_4)
  SELECT g, g * 10, g * 100 FROM generate_series(1, 100) AS g;

-- function to duplicate record
CREATE OR REPLACE FUNCTION fn_history_duplicate(p_history_id integer) RETURNS SETOF history AS
$BODY$
DECLARE
  cols text;
  insert_statement text;
BEGIN

  -- build list of columns
  SELECT array_to_string(array_agg(column_name::name), ',') INTO cols
    FROM information_schema.columns 
    WHERE (table_schema, table_name) = ('public', 'history')
    AND column_name <> 'history_id';

  -- build insert statement
  insert_statement := 'INSERT INTO history (' || cols || ') SELECT ' || cols || ' FROM history WHERE history_id = $1 RETURNING *';

  -- execute statement
  RETURN QUERY EXECUTE insert_statement USING p_history_id;

  RETURN;

END;
$BODY$
  LANGUAGE 'plpgsql';

-- test
SELECT * FROM fn_history_duplicate(1);
 history_id | col_2 | col_3 | col_4 |           datetime            
------------+-------+-------+-------+-------------------------------
        101 |     1 |    10 |   100 | 2013-04-15 14:56:11.131507+00
(1 row)

正如我在原始评论中所指出的,您还可以查看colnames 扩展作为查询信息模式的替代方法。

于 2013-04-15T15:29:07.780 回答
1

无论如何您都不需要更新,您可以直接在SELECT语句中提供常量值:

INSERT INTO history 
SELECT NEXTVAL('history_id_seq'), 
       col_1, 
       col_2, 
       col_3, 
       col_4, 
       'test_5', 
       ... 
       'test_23', 
       ...,
       col_100
FROM history
WHERE history_sid = 1234
ORDER BY datetime DESC
LIMIT 1
 RETURNING history_sid INTO new_history_sid;
于 2013-04-15T08:57:54.137 回答