简体   繁体   English

编写Postgres获取或创建SQL查询

[英]Write a Postgres Get or Create SQL Query

I want to write a single Postgres SQL statement that says look for a user with color X and brightness Y. If that user exists, return all of its row data. 我想写一个Postgres SQL语句,说明寻找具有颜色X和亮度Y的用户。如果该用户存在,则返回其所有行数据。 If not, create a new row and pass additional information. 如果没有,请创建一个新行并传递其他信息。 The two separate statements would do something like this: 这两个单独的陈述会做这样的事情:

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

If that doesn't return anything, then execute this: 如果这不返回任何内容,则执行以下命令:

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

Is there a way to combine these into a single query?? 有没有办法将这些组合成一个查询?

In a SQL DBMS, the select-test-insert approach is a mistake: nothing prevents another process from inserting the "missing" row between your select and insert statements. 在SQL DBMS中,select-test-insert方法是一个错误:没有什么可以防止另一个进程在selectinsert语句之间插入“missing”行。 Do this instead: 改为:

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

You should be able to pass that entire text as a single "query" to the DBMS. 您应该能够将整个文本作为单个“查询”传递给DBMS。 You might want to consider making it into a stored procedure. 您可能需要考虑将其变为存储过程。

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

If your columns participate in unique index constraint you can use an approach which is avaible since version 9.5: 如果您的列参与唯一索引约束,则可以使用自9.5版以来可用的方法:

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

(assuming you have unique index on color ). (假设你有独特的color索引)。

Docs are gere: https://www.postgresql.org/docs/9.5/static/sql-insert.html 文档是gere: https ://www.postgresql.org/docs/9.5/static/sql-insert.html

Adding my solution here. 在此添加我的解决方案 It is a tad different than @Clodoaldo Neto and @astef's solutions. 它与@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';

I found astef's solution inadequate for my purposes: it doesn't perform the "get" portion of "get or create"! 我发现astef的解决方案不适合我的目的:它不执行“获取或创建”的“获取”部分! If the value already existed, nothing would happen. 如果该值已存在,则不会发生任何事情。

The union at the end of the statement ensures that if the value was not inserted (since it already existed) we still retrieve that value from the table. 语句末尾的联合确保如果未插入值(因为它已经存在),我们仍然从表中检索该值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM