编写Postgres获取或创建SQL查询

Eri*_* H. 12 sql postgresql

我想写一个Postgres SQL语句,说明寻找具有颜色X和亮度Y的用户.如果该用户存在,则返回其所有行数据.如果没有,请创建一个新行并传递其他信息.这两个单独的陈述会做这样的事情:

Select (color, brightness, size, age) FROM mytable WHERE color = 'X' AND brightness= 'Y';
Run Code Online (Sandbox Code Playgroud)

如果这不返回任何内容,则执行以下命令:

INSERT INTO mytable (color, brightness, size, age) VALUES (X, Y, big, old);
Run Code Online (Sandbox Code Playgroud)

有没有办法将这些组合成一个查询?

Jam*_*den 21

在SQL数据库管理系统,选择试验插入的做法是错误的:没有什么能阻止另一进程将您的"失踪"的行selectinsert语句.改为:

insert into mytable (color, brightness, size, age)
select color, brightness, size, age 
from mytable
where not exists (
    select 1 from 
    from mytable
    where color = 'X' and brightness = 'Y'
);
SELECT (color, brightness, size, age) 
FROM mytable 
WHERE color = 'X' AND brightness= 'Y';
Run Code Online (Sandbox Code Playgroud)

您应该能够将整个文本作为单个"查询"传递给DBMS.您可能需要考虑将其变为存储过程.

  • 无法理解这个答案是如何收集到这么多包含语法错误的投票的。Postgres 中的 INSERT 没有选项 `insert ... where ...`。您可能的意思是“插入 mytable(颜色、亮度、大小、年龄)SELECT 'X', 'Y', 1.2, 3.4 where not exists...`。 (2认同)

Clo*_*eto 6

with sel as (
    select color, brightness, size, age
    from mytable
    where color = 'X' and brightness = 'Y'
), ins as (
    insert into mytable (color, brightness, size, age)
    select 'X', 'Y', 6.2, 40
    where not exists (
        select 1 from sel
    )
    returning color, brightness, size, age
)
select color, brightness, size, age
from ins
union
select color, brightness, size, age
from sel
Run Code Online (Sandbox Code Playgroud)


ast*_*tef 5

如果您的列参与唯一索引约束,您可以使用自版本 9.5 以来可用的方法:

INSERT INTO mytable (color, brightness, size, age)
VALUES ('X', 'Y', 'big', 'old')
ON CONFLICT (color) DO NOTHING;
Run Code Online (Sandbox Code Playgroud)

(假设您有唯一索引color)。

文档在这里:postgresql 9.5

  • 这并没有回答问题,该问题询问如何“获取”或“创建”一行。 (3认同)

Bri*_*lli 5

在此处添加我的解决方案。它与@Clodoaldo Neto 和@astef 的解决方案略有不同。

WITH ins AS (
  INSERT INTO mytable (color, brightness, size, age)
  VALUES ('X', 'Y', 'big', 'old')
  ON CONFLICT (color) DO NOTHING
  RETURNING *
)
SELECT * FROM ins
UNION
SELECT * FROM mytable
  WHERE color = 'X';
Run Code Online (Sandbox Code Playgroud)

我发现 astef 的解决方案不足以满足我的目的:它不执行“获取或创建”的“获取”部分!如果该值已经存在,则什么都不会发生。

语句末尾的联合确保如果值没有插入(因为它已经存在),我们仍然从表中检索该值。

  • 我发现了上面的一个问题:如果存在冲突,您的表的序列 ID 计数器将在每次执行查询时递增。这并不理想。 (3认同)