从可能为空的表中使用SELECT进行INSERT

时间:2016-02-02 18:30:05

标签: postgresql

我有一个postgres数据库架构,其中新插入的行引用其他行。表格的骨架是:

CREATE TABLE table_1 (
    f1    UUID PRIMARY KEY,
    f2    UUID NOT NULL,
    f3    text NOT NULL,
    f4    text NOT NULL DEFAULT '',
    f5    text NOT NULL DEFAULT '',
    f6    UUID NULL,
);

这是我使用的INSERT查询:

INSERT INTO table_a (f1, f2, f3, f4, f5, f6)
SELECT               $1, $2, $3, f4, f5, f2
FROM        table_a
WHERE       <conditionals>
ORDER BY    <ordering>
LIMIT       1

基本思想是我寻找满足条件的现有行。如果存在,则使用字段f4,f5和f2填充要插入的新行中的字段f4,f5和f6。如果不存在,那么这些字段应该采用默认值(分别为&#39;&#39;&#39;&#39;和NULL)。

问题是,如果没有找到行,SELECT本身似乎没有返回结果,只是跳过整个插入。如果一行匹配条件,它可以正常工作,但如果该SELECT没有返回任何行则不行。我怎样才能获得理想的行为?

2 个答案:

答案 0 :(得分:3)

insert into table_a (f1, f2, f3, f4, f5, f6)
select f1, f2, f3, f4, f5, f6
from (
    (
        select $1, $2, $3, f4, f5, f2, 1
        from table_a
        where <conditionals>
        order by <ordering>
        limit 1
    ) s
    union all
    select $1, $2, $3, '', '', null, 2
) s (f1, f2, f3, f4, f5, f6, o)
order by o
limit 1

答案 1 :(得分:1)

如果您想在查询中使用表DDL中的默认值而不是硬编码,则另一种方式:

WITH t AS (
  INSERT INTO table_a (f1, f2, f3, f4, f5, f6)
  SELECT               $1, $2, $3, f4, f5, f2
  FROM        table_a
  WHERE       <conditionals>
  ORDER BY    <ordering>
  LIMIT       1
  RETURNING *) -- This query will return inserted values
INSERT INTO table_a (f1, f2, f3)
SELECT $1, $2, $3 WHERE (SELECT count(*) FROM t) = 0; -- Insert if no insertion was happened at WITH clause