【问题标题】:Insert if not exists, else return id in postgresql如果不存在则插入,否则在 postgresql 中返回 id
【发布时间】:2013-08-14 02:15:15
【问题描述】:

我在 PostgreSQL 中有一个包含三列的简单表:

  • id 序列主键
  • key varchar
  • 值 varchar

我已经在这里看到了这个问题:Insert, on duplicate update in PostgreSQL?,但我想知道如果它存在,如何获取 id,而不是更新。如果标准做法是始终“插入”或“如果存在则更新”,这是为什么呢?执行 SELECT (LIMIT 1) 的成本是否高于执行 UPDATE?

我有以下代码

INSERT INTO tag
    ("key", "value")
    SELECT 'key1', 'value1'
WHERE
    NOT EXISTS (
        SELECT id,"key","value" FROM tag WHERE key = 'key1' AND value = 'value1'
    );

从某种意义上说,如果存在它就不会插入,但我想获取 id。是否有一个“返回 id”子句或类似的东西我可以在那里点击?

【问题讨论】:

标签: postgresql


【解决方案1】:

是的,有returning

INSERT INTO tag ("key", "value")
SELECT 'key1', 'value1'
WHERE NOT EXISTS (
    SELECT id, "key", "value"
    FROM node_tag
    WHERE key = 'key1' AND value = 'value1'
    )
returning id, "key", "value"

如果该行已经存在则返回该行

with s as (
    select id, "key", "value"
    from tag
    where key = 'key1' and value = 'value1'
), i as (
    insert into tag ("key", "value")
    select 'key1', 'value1'
    where not exists (select 1 from s)
    returning id, "key", "value"
)
select id, "key", "value"
from i
union all
select id, "key", "value"
from s

如果该行不存在,则返回插入的行,否则返回现有行。

顺便说一句,如果“key”/“value”对使其唯一,那么它就是主键,不需要 id 列。除非“键”/“值”对中的一个或两个可以为空。

【讨论】:

  • 经过仔细检查,我意识到这个解决方案实际上并没有像我希望的那样做,因为它不会返回任何东西,除非 INSERT 有效(即,如果键值对以前不在表中)。如果该行已经在表中,它只会返回空白(不是预期的 ID)。我之前错过的原因是我在测试它时不小心打错了(所以键值对不在表中,因此它返回了行的 ID)。
  • 顺便说一句:可能是UNION ALL,恕我直言。
  • @wildplasser 请注意,无论使用all,总是只会返回一行。
  • 语义上你是对的。但我严重怀疑优化者是否会意识到这一点。 (当然是徒劳的)
  • 单行可以忽略不计。但它可能会影响计划生成/选择(只有在涉及多个行时才能检测到)删除重复项并不是那么昂贵 ansich 但它可能会迫使两个子计划产生他们的@ 987654326@ 按特定顺序(不需要)
【解决方案2】:

您可以将返回到变量的值存储为... RETURNING field1, field2,... INTO var1, var2,...

RETURNING 通常会返回一个查询,如果您在 plpgsql 中调用它而不使用其返回的结果集,该查询将返回错误 'query has no destination for result data'。

【讨论】:

    【解决方案3】:
    with vals as (
      select 'key5' as key, 'value2' as value
    )
    insert into Test1 (key, value)
    select v.key, v.value
    from vals as v
    where not exists (select * from Test1 as t where t.key = v.key and t.value = v.value)
    returning id
    

    sql fiddle demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-28
      • 2013-06-18
      • 2013-12-27
      • 1970-01-01
      • 1970-01-01
      • 2017-02-10
      相关资源
      最近更新 更多