18

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

Select (color, brightness, size, age) FROM mytable WHERE color = 'X' AND brightness= 'Y';

如果这没有返回任何东西,那么执行这个:

INSERT INTO mytable (color, brightness, size, age) VALUES (X, Y, big, old);

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

4

4 回答 4

27

在 SQL DBMS 中,select-test-insert 方法是一个错误:没有什么能阻止另一个进程在您的selectandinsert语句之间插入“缺失”行。改为这样做:

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';

您应该能够将整个文本作为单个“查询”传递给 DBMS。您可能需要考虑将其制成存储过程。

于 2013-04-21T04:52:36.680 回答
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
于 2013-04-20T20:51:45.063 回答
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';

我发现 astef 的解决方案不适合我的目的:它不执行“获取或创建”的“获取”部分!如果该值已经存在,则不会发生任何事情。

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

于 2017-01-02T16:43:50.467 回答
3

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

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

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

文档是基尔:https ://www.postgresql.org/docs/9.5/static/sql-insert.html

于 2016-08-01T10:06:09.343 回答