1

我正在尝试将bytea数据从一个表移动到另一个表,更新一个查询中的引用。

因此,我想从用于插入的查询中返回未用于插入的数据。

INSERT INTO file_data (data)
  select image from task_log where image is not null
RETURNING id as file_data_id, task_log.id as task_log_id

但我收到该查询的错误:

[42P01] ERROR: missing FROM-clause entry for table "task_log"

我想做类似的事情:

WITH inserted AS (
  INSERT INTO file_data (data)
    SELECT image FROM task_log WHERE image IS NOT NULL
  RETURNING id AS file_data_id, task_log.id AS task_log_id
)
UPDATE task_log
SET    task_log.attachment_id = inserted.file_data_id,
       task_log.attachment_type = 'INLINE_IMAGE'
FROM   inserted
WHERE  inserted.task_log_id = task_log.id;

但是我无法获取用于插入的所有数据,我无法从子选择中返回 id。

这个答案启发了我如何使用Common Table Expressions做到这一点,但我找不到让它工作的方法。

4

2 回答 2

2

您需要正确设置表名和别名。另外,两个表之间的连接是列imagedata在新表中file_data):

WITH inserted AS (
  INSERT INTO file_data (data)
  SELECT image
  FROM   task_log
  WHERE  image IS NOT NULL
  RETURNING id, data  -- can only reference target row
)
UPDATE task_log t
SET    attachment_id = i.id
     , attachment_type = 'INLINE_IMAGE'
FROM   inserted i
WHERE  t.image = i.data;

就像我在您引用的旧答案中所解释的那样,它image必须是唯一的task_log才能起作用:

我添加了一种技术,如何在引用的答案中消除非唯一值的歧义。不过,不确定您是否想要重复的图像file_data

RETURNINGan 的子句中,INSERT您只能引用插入行中的列。手册:

可选RETURNING子句导致INSERT根据实际插入的每一行计算和返回值 (...) 但是,任何使用表列的表达式都是允许的

大胆强调我的。

折叠重复的源值

如果您希望INSERT( task_log) 的目标表中有不同的条目,那么在这种情况下,您只需要在DISTINCT初始SELECT:

WITH inserted AS (
  INSERT INTO file_data (data)
  SELECT DISTINCT image  -- fold duplicates
  FROM   task_log
  WHERE  image IS NOT NULL
  RETURNING id, data  -- can only reference target row
)
UPDATE task_log t
SET    attachment_id = i.id
     , attachment_type = 'INLINE_IMAGE'
FROM   inserted i
WHERE  t.image = i.data;

结果file_data.idtask_log. 请注意,task_log现在中的多行指向file_data. 小心更新和删除...

于 2017-11-09T13:50:00.793 回答
0

我需要复制重复项,所以我最终为使用的数据行的 id添加了一个临时列

alter table file_data add column task_log_id bigint;
-- insert & update data
alter table file_data drop column task_log_id;

完整的移动脚本是

-- A new table for any file data
CREATE TABLE file_data (
  id         BIGSERIAL PRIMARY KEY,
  data  bytea
);

-- Move data from task_log to bytes

-- Create new columns to reference file_data
alter table task_log add column attachment_type VARCHAR(50);
alter table task_log add column attachment_id bigint REFERENCES file_data;

-- add a temp column for the task_id used for the insert
alter table file_data add column task_log_id bigint;

-- insert data into file_data and set references
with inserted as (
  INSERT INTO file_data (data, task_log_id)
    select image, id from task_log where image is not null
  RETURNING id, task_log_id
)
UPDATE task_log
SET   attachment_id = inserted.id,
      attachment_type = 'INLINE_IMAGE'
FROM  inserted
where inserted.task_log_id = task_log.id;
-- delete the temp column
alter table file_data drop column task_log_id;
-- delete task_log images
alter table task_log drop column image;

由于这会产生一些死数据,因此我vacuum full随后运行了一个清理数据。

但请让我重复来自@ErwinBrandstetter 的警告:

性能比我在链接答案中提出的使用序列号的方法差得多。添加和删​​除列需要所有者的权限、全表重写和表上的排他锁,这对并发访问是有害的。

于 2017-11-10T09:24:41.160 回答